[cprg]$ cat test.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
int i=10;
printf("i=%d\ni++=%d\n++i=%d\n",i,i++,++i);
return 0;
}
[cprg]$ make
gcc -g -Wall -o test test.c
test.c: In function ‘main’:
test.c:7: warning: operation on ‘i’ may be undefined
test.c:7: warning: operation on ‘i’ may be undefined
[cprg]$ ./test
i=12
i++=11
++i=12
I have no idea why this thing is happening. Please can anyone explain me in detail as to what is happening here ?
C does not define in which order function call arguments get evaluated. You are in for trouble there ;).
Update:
To clarify what is defined and what not:
The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.
From ISO/IEC 9899:1999, Section 6.5.2.2, Function calls
Here's the disassembly of main (the part we need):
0x080483ed <+9>: movl $0xa,0x1c(%esp) # initializes i
0x080483f5 <+17>: addl $0x1,0x1c(%esp) # i += 1
0x080483fa <+22>: mov 0x1c(%esp),%edx # edx = i = 11
0x080483fe <+26>: addl $0x1,0x1c(%esp) # i += 1
0x08048403 <+31>: mov $0x80484f0,%eax # address of string
0x08048408 <+36>: mov 0x1c(%esp),%ecx # ecx = i = 12
0x0804840c <+40>: mov %ecx,0xc(%esp) # pushes ecx (++i)
0x08048410 <+44>: mov %edx,0x8(%esp) # and edx (i++)
0x08048414 <+48>: mov 0x1c(%esp),%edx # now gets edx (i)
0x08048418 <+52>: mov %edx,0x4(%esp) # and pushes it
0x0804841c <+56>: mov %eax,(%esp) # push address of string
0x0804841f <+59>: call 0x804831c <printf@plt> # write
now, since arguments are pushed on the stack in reverse order, the disassembly shows that the first that is pushed is ecx, so we can assume it's ++i (since it's the last argument in printf), so edx is i++. Strangely, it decides to compute first i++, then ++i. At the end it loads i and pushes it, but, at this point, i has been increased two times, so it's 12. This is really undefined behavior! Look:
printf("++i=%d\ni++=%d\ni=%d\n",++i,i++,i);
produces:
++i=12
i++=10
i=12
Check this StackOverflow link for further information on argument evaluation order:
Compilers and argument order of evaluation in C++
It has to do with evaluation order of i
, i++
and ++i
expression on C. As an example is OK, but in real code do not rely on that order if you want to avoid weird issues.
精彩评论