confusing C code, someone explain it for me?
The evaluation order does matter a lot, s开发者_JS百科o, is this something called non-referential-transparency?
int i = 1;
int counter(){
i = i + 1;
return i;
}
int foo(int i, int j){
return i*2 + 3*j;
}
int main(){
printf("%d", foo(counter(), counter()));
}
I guess what you might have in mind is that the evaluation order of function parameters is not standardized in C. Since counter()
will return a different result on each call, and the result of foo(2, 3)
is different from that of foo(3, 2)
, compiling and executing this code may give you different results on different platforms.
On the same platform, however, it is deterministic, as others have explained well. [Update] (To be precise: once compiled into an executable on a specific platform with specific compiler options, all executions will produce the same output. However, as commenters pointed out, it might even produce different output on the same platform when built with different compilation options.)[/Update]
Strictly speaking, the code in question might give different results even when compiled on the same platform with the same compiler and settings. The order in which function arguments are evaluated is unspecified. The C standard defines "unspecified behavior" as
use of an unspecified value, or other behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance (C99 §3.4.4/1).
The important part is that "in any instance" the implementation might do something different, so, for example, your compiler could emit code that randomly selects the order in which to evaluate the arguments.
Obviously, it is highly unlikely that any implementation would evaluate the arguments to a function differently during different runs of the same program.
The point is that you should never rely on the order in which function arguments are evaluated; in a correct program, it should not matter.
It is deterministic, it will return the same values every time.
counter()
will return a different number each time you call it because i
is global. However, a global variable only keeps it value during an execution. If you restart the program, it gets the value 1 and starts again!
Several answers have indicated that while different platforms might give different results, the result is deterministic on a given platform.
This is not correct
The C99 Standard says (6.5/3 Expressions):
Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.
So, the order of evaluation of the parameters in the call to foo()
is not specified by the standard. The order that the 2 calls to counter()
cannot be counted on. A particular compiler could order the calls differently depending on:
- the optimizations the compiler is asked to perform
- the exact set of code (include files, slightly or significantly different source code in the translation unit, whatever)
- the day of the week the program is built
- a random number
While it's unlikely that things other than the optimizations used, differences in other compiler options, or differences in the translation unit will result in a different ordering of the argument evaluation (since there probably wouldn't be much reason for the compiler to generate different output), the fact is you simply can't depend on the ordering.
In fact, it's even OK (as far as the standard is concerned) for the order of evaluation of the call to be made differently each time foo()
is invoked. For example, say your example program looked like (to make what's happening when more obvious):
#include <stdio.h>
int i = 1;
int counter1(){
i = i * 3;
printf( "counter1()\n");
return i;
}
int counter2(){
i = i * 5;
printf( "counter2()\n");
return i;
}
int foo(int i, int j){
return i + j;
}
int main(){
int x;
for (x=0; x<2; ++x) {
printf("%d\n", foo(counter1(), counter2()));
}
return 0;
}
It would be perfectly valid for the output to look like any of the following (note there's at least one additional possibility):
Possibility 1:
counter1()
counter2()
18
counter1()
counter2()
270
Possibility 2:
counter1()
counter2()
18
counter2()
counter1()
300
Possibility 3:
counter2()
counter1()
20
counter2()
counter1()
300
It would be OK (even if very weird) for the compiler to evaluate the arguments differently each time that line of code is executed, but it's permitted by the fact that the order is unspecified by the standard.
While it's highly unlikely that the evaluation would be 'randomized', I do think that such difficult to control things as the optimization level (or other compiler settings), the precise version/patch level of the compiler, or even the exact code that surrounds the expressions could cause the compiler to chose to a different evaluation path.
Relying on the order of evaluation of function arguments, even on a particular platform, is flirting with danger.
As a side note, this is one of the reasons that having hidden side-effects in a function is something to avoid if possible.
The code is deterministic but what it prints may depend on the compiler because foo
may receive 2,3 or 3,2.
As Code Clown has mentioned the code is deterministic. It would give you the same output on same "compiler".
C standard doesn't specify order of evaluation of method call arguments. So which of the two calls to method foo will get called first is up to the compiler to decide.
The function foo() is not referentially transparent. Referential transparency means the function should return the same value when called on same input. For this to happen the function has to be pure, that is it should not have any side effects.
C language doesn't guarantee a function to be pure, one has to manage it oneself by:
- not storing the formal arguments of a method inside a local static field
- not depending on value of global variable
(there are many ways to make a function referentially opaque, these are more common)
Here subsequent calls to counter() result in different values so it is referentially opaque.
精彩评论