0

When I run the following code, I get the output: 0 0 2 0 0

int main(){

    static int var[5];
    int count=0;
     
    var[++count]=++count;
    for(count=0;count<5;count++)
    { 
      printf("%d ",var[count]);
    }
    return 0;
}
user438383
  • 5,716
  • 8
  • 28
  • 43

1 Answers1

1

The statement var[++count]=++count; induces undefined behavior according to the C17 standard 6.5.2:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.)

Thus, for each unique variable, it holds that if it is pre-incremented, then its value may not be used elsewhere in that expression. The result will be that the variable is incremented first, and its incremented value is then used in the expression.

The code is technically undefined behavior. What (probably) happened in practice, is that count was incremented twice and then used both as an index and a value.

Yun
  • 3,056
  • 6
  • 9
  • 28
  • Good point, thank you! I've updated the answer. – Yun Aug 14 '21 at 12:51
  • 1
    I believe it would also be undefined if only one of the "count" uses were preindexed. The expression is ambiguous, with the result varying with chosen execution order. There is no implicit left-to-right or right-to-left ordering. The elements of the syntactic parse tree may be executed in any order -- including inconsistently. Although a compiler may detect this case, a simpler case could occur if "count" were a function, say "Count()”. The compiler may have no knowledge of the actions of "Count()” when it generates the code that calls it. – cmm Aug 14 '21 at 12:56
  • “Thus, only one pre-increment operator can be used in an expression” is incorrect for multiple reasons: Pre-increment operators can be used on different lvalues, and some expressions include sequencing that render multiple uses of the pre-increment operator (and others) defined. – Eric Postpischil Aug 14 '21 at 13:01
  • @cmm: “The elements of the syntactic parse tree may be executed in any order”: This is not quite true, although it does not affect the situation at hand. The side effect of updating the stored value of the left operand of `=` is sequenced after the value computations of the left and right operands (C 2018 6.5.16 3). Thus, if somebody wrote `x = 3; x = (f(x), 4);`, `f` must be called with an argument of 3; the assignment of 4 cannot be performed first. (The comma operator also has a sequence point, but that only orders its own operands; it does not affect the expression outside of that.) – Eric Postpischil Aug 14 '21 at 13:06
  • Eric, agreed. I was limiting my thinking to the tree for unsequenced operators. If I remember correctly, comma in the context of your example (which acts like a LISP prog2 function) sequences, but it does not sequence in the context of a parameter list. Parameters may be evaluated in any order. – cmm Aug 14 '21 at 13:11
  • @EricPostpischil Thank you. Would `func(++a, ++b)` be a good counterexample? – Yun Aug 14 '21 at 13:13
  • Yes: `fun(++a, ++b)` is well defined in the absence of preprocessor tampering. – Jonathan Leffler Aug 14 '21 at 13:22
  • Thank you. That was imprecise writing on my part. I've updated the answer. – Yun Aug 14 '21 at 13:23