Does 'a[i] = i;' always result in well def

2019-03-14 23:38发布

There are several interesting questions raised here regarding undefined behaviour in C. One of them is (slightly modified)

Does the following piece of code result in undefined behaviour?

int i = 0, *a = &i;   // Line 1
a[i] = i + 1;         // Line 2

Since there is no concrete answer to this part of the question there, and I am interested in knowing the behaviour in C++, I am raising it again here.


Rule #2 from Undefined Behavior and Sequence Points says

Furthermore, the prior value shall be accessed only to determine the value to be stored

Clearly in the example above, the value is being accessed twice: a[i] (lhs) and i (rhs), and only one of them (the rhs) determines the value to be stored.

Does Line 2 violate the rule above and result in undefined behaviour in C++03?


There is some confusion as to whether i is modified at Line 2?

Yes it is modified!

6条回答
对你真心纯属浪费
2楼-- · 2019-03-14 23:52

I would like to point out one thing: a[i] = i does not always lead to well defined behaviour. The reason why the behaviour is well defined in the case specified, is because of the initial values i and a.

Let me elaborate:

int i = 1, *a = &i;   // Line 1, i initialized to anything other than 0
a[i] = i + 1;         // Line 2, all of a sudden we are in buffer over/underflow

For any other initial value of i we are accessing a different memory location from that of i itself, which produces undefined behaviour.

查看更多
Rolldiameter
3楼-- · 2019-03-14 23:55

No it doesn't. The first line has a sequence point (the comma), so it is not undefined behaviour:

int i = 0, *a = &i;

The second line is perfectly normal.

a[i] = i + 1;

Since i + 1 creates a temporary value, i gets modified only once, on the assignment. This however would be undefined behaviour:

a[i] = i++;
查看更多
别忘想泡老子
4楼-- · 2019-03-14 23:56

Undefined behavior in this case would only take place if you modify the same memory address without a sequence point between the modifications. Specifically, the C99 spec, section 6.5/2 states,

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.

In your case no modification of the same memory address takes place between sequence points, therefore there is no undefined behavior.

查看更多
女痞
5楼-- · 2019-03-15 00:01

Let us decompose the expression a[i] = i + 1 will you ?

= -- [] -- a
  \     \_ i
   \
    \_ + -- i
         \_ 1

Effectively, a[i] refers to &i however note that neither a[i] nor i+1 modifies i. i is only modified when = (the assignment itself) is executed.

Since the operands of any function need be evaluated before this function takes effect, this is actually equivalent to:

void assign(int& address, int value) { address = value; }

assign(a[i], i + 1);

It is true that = is somewhat special in that it is built-in and does not result in a function call, still the evaluation of both operands are sequenced before the actual assignment, so they are first evaluated prior to i being modified, and a[i] (which points to i location) is being assigned to.

查看更多
【Aperson】
6楼-- · 2019-03-15 00:04

int i = 0, *a = &i;

there is a sequence point between declarations, therefore no UB here. However take a note that it is a bad idea to declare/define variables that way. Any normal coding standard would tell you declare one variable per line.

a[i] = i;

The i is not changed in any way, therefore no UB here either.

查看更多
我命由我不由天
7楼-- · 2019-03-15 00:12

This will result in undefined behavior in C++03, and well-defined behavior in C++11.

C++03: Undefined Behvaior

From the C++03 standard, section 5 paragraph 4:

Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.

Note the second sentence: The previous value of i can only be used to determine the value to be stored. But here it is also used to determine the array index. So because this assignment will modify i, a[0] = i+1 is well defined, while a[i] = i+1 is not. Note that the assignment does not generate a sequence point: only the end of the full expression (the semicolon) does.


C++11: Well defined behavior:

C++11 got rid of the notion of sequence points, and instead defines which evaluations are sequenced before which.

From the standard, section 1.9 paragraph 15:

The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

Both operands of the assignment operator are sequenced before the actual assignment. So both a[i] and i+1 will be evaluated, and only then will i be modified. The result is well defined.

查看更多
登录 后发表回答