Question

I was just going though my text book when I came across this question:

What would be the value of a after the following expression? Assume the initial value of a = 5. Mention the steps.

a+=(a++)+(++a)

At first I thought this is undefined behaviour because a has been modified more than once. Then I read the question and it said "Mention the steps" so I probably thought this question is right.

  • Does applying parentheses make an undefined behaviour defined?
  • Is a sequence point created after evaluating a parentheses expression?
  • If it is defined,how do the parentheses matter since ++ and () have the same precedence?
Was it helpful?

Solution

No, applying parentheses doesn't make it a defined behaviour. It's still undefined. The C99 standard §6.5 ¶2 says

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 read only to determine the value to be stored.

Putting a sub-expression in parentheses may force the order of evaluation of sub-expressions but it does not create a sequence point. Therefore, it does not guarantee when the side effects of the sub-expressions, if they produce any, will take place. Quoting the C99 standard again §5.1.2.3¶2

Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.

For the sake of completeness, following are sequence points laid down by the C99 standard in Annex C.

  1. The call to a function, after the arguments have been evaluated.

  2. The end of the first operand of the following operators: logical AND &&; logical OR ||; conditional ?; comma ,.

  3. The end of a full declarator.

  4. The end of a full expression; the expression in an expression statement; the controlling expression of a selection statement (if or switch); the controlling expression of a while or do statement; each of the expressions of a for statement; the expression in a return statement.

  5. Immediately before a library function returns.

  6. After the actions associated with each formatted input/output function conversion specifier.

  7. Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call.

OTHER TIPS

Adding parenthesis does not create a sequence point and in the more modern standards it does not create a sequenced before relationship with respect to side effects which is the problem with the expression that you have unless noted the rest of this will be with respect to C++11. Parenthesis are a primary expression covered in section 5.1 Primary expressions, which has the following grammar (emphasis mine going forward):

primary-expression:
  literal
  this
  ( expression )
  [...]

and in paragraph 6 it says:

A parenthesized expression is a primary expression whose type and value are identical to those of the enclosed expression. The presence of parentheses does not affect whether the expression is an lvalue. The parenthesized expression can be used in exactly the same contexts as those where the enclosed expression can be used, and with the same meaning, except as otherwise indicated.

The postfix ++ is problematic since we can not determine when the side effect of updating a will happen pre C++11 and in C this applies to both the postfix ++ and prefix ++ operations. With respect to how undefined behavior changed for prefix ++ in C++11 see Assignment operator sequencing in C11 expressions.

The += operation is problematic since:

[...]E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once[...]

So in C++11 the following went from undefined to defined:

a = ++a + 1 ;

but this remains undefined:

a = a++ + 1 ;

and both of the above are undefined pre C++11 and in both C99 and C11.

From the draft C++11 standard section 1.9 Program execution paragraph 15 says:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. —end note ] 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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top