Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is calling a function with local side-effects twice in the same expression undefined behavior?

int f() {
    static int i=0;
    return ++i;
}
int g() {
    return f() + f();
}

Does g() return 3 or is the result undefined?

like image 318
l4m2 Avatar asked Nov 10 '16 16:11

l4m2


3 Answers

Chapter and verse:

6.5.2.2 Function calls
...
10     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.94)
94) In other words, function executions do not ‘‘interleave’’ with each other

Upshot is that there is a sequence point between each ++i by virtue of it being part of a function call. Thus, this behavior is well-defined.

Whether it actually does what you intend is another matter. Note that at some point you risk signed overflow, which is undefined. And as others have pointed out, f() - f() may not give the result you would expect (left to right evaluation is not guaranteed in that case).

like image 192
John Bode Avatar answered Nov 09 '22 01:11

John Bode


The evaluations of the two operands of the + operator are unsequenced1.

There is a sequence point just before the actual function call2. This sequence point is enough to separate the modifications of static variable i, making the entire expression indeterminately sequenced, and the order of the function calls unspecified3.

Thus the behavior remains defined, and the first call to function g will always yield 3, since the unspecified order of the function calls doesn't influence the result.

A program containing unspecified behavior is defined4.


(All quotes are from: ISO/IEC 9899:201x)

1 (6.5 Expressions 3)
Except as specified later, side effects and value computations of subexpressions are unsequenced.

2 (6.5.2.2 Function calls 10)
There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call.

3 (5.1.2.3 Program execution 3)
Evaluations A and B are indeterminately sequenced when A is sequenced either before or after B, but it is unspecified which.

4 (4. Conformance 3)
A program that is correct in all other aspects, operating on correct data, containing unspecified behavior shall be a correct program and act in accordance with 5.1.2.3.

like image 34
2501 Avatar answered Nov 09 '22 01:11

2501


There is no reason for this to be undefined, because + operation is commutative, and because there are sequence points for the two ++ operations to be sequenced.

C standard has sequence points after a full expression, and also before a function is entered in a function call. Therefore, the results of ++ will be fully sequenced. Moreover, since + is commutative, the order of calls to f() does not change the result.

Note that the same logic would not apply to

return f() - f();

because - is not commutative. The result of the expression above is unspecified, i.e. a standard-compliant compiler could reasonably produce a 1 or a -1, depending on the order in which the compiler calls the two f() functions.

like image 11
Sergey Kalinichenko Avatar answered Nov 09 '22 02:11

Sergey Kalinichenko