Is foo(i++) + foo(i++) undefined in ANSI C?

前端 未结 1 1216
渐次进展
渐次进展 2021-01-20 06:54

Here\'s an example snippet:

int i = 4,b;    
b = foo(i++) + foo(i++);

I\'m pretty certain it\'s not undefined, because the

1条回答
  •  隐瞒了意图╮
    2021-01-20 07:33

    The behavior is undefined.

    b = foo(i++) + foo(i++);
    

    As you say, there's a sequence point between the evaluation of the first i++ and the call to foo, and likewise between the evaluation of the second i++ and the call foo. But there isn't (necessarily) a sequence point between the two evaluations of i++, or more specifically between their side effects (modifying i).

    Quoting the N1570 draft of the 2011 ISO C standard, section 6.5.2.2p10:

    There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call. Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

    The second sentence is significant here: the two evaluations of i++ are "indeterminately sequenced" with respect to the two function calls, meaning that they can occur either before or after the calls to foo. (They're not unsequenced, though; each of them occurs either before or after the calls, but it's unspecified which.)

    And 6.5p2 says:

    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.

    Putting this together, a conforming implementation could evaluate the expression in this order:

    1. Evaluate the first i++ and save the value somewhere.
    2. Evaluate the second i++and save the value somewhere.
    3. Call foo, passing the first saved value as an argument.
    4. Call foo, passing the second saved value as an argument.
    5. Add the two results.
    6. Store the sum in b.

    There is no sequence point between steps 1 and 2, both of which modify i, so the behavior is undefined.

    (That's actually a slight oversimplification; the side effect of modifying i can be separated from the determination of the result of i++.

    Bottom line: We know that

    b = i++ + i++;
    

    has undefined behavior, for reasons that have been explained repeatedly. Wrapping the i++ subexpressions in function calls does add some sequence points, but those sequence points don't separate the two evaluations of i++ and therefore don't cause the behavior to become well defined.

    Even bottommer line: Please don't write code like that. Even if the behavior were well defined, it would be more difficult than it's worth to prove it and to determine what the behavior should be.

    0 讨论(0)
提交回复
热议问题