开发者

Strange printf behaviour? [duplicate]

This question already has answers here: Why are these constructs using pre and post-increment undefined behavior? (14 answers) 开发者_如何学Python Closed 5 years ago.
[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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜