简体   繁体   中英

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

Here's an example snippet:

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

I'm pretty certain it's not undefined, because there is a sequence point before the invocation of foo . However, if I compile the code with the -Wall flag a compiler warning is generated which says warning: operation on 'i' may be undefined . I realize it says may , but I'd just like to double check if I'm correct.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM