C: printf参数执行顺序与前置后置自增自减的影响

起源: 今天在了解反作用side-effect的过程当中,看到了下面的网页,把我带到了由printf引发的一系列问题,纠结了一成天,勉强弄懂。html

 

第一个代码没什么好解释的。而第二个printf("return of swap is %d\tx=%d,y=%d\n",swap(&x,&y),x,y)竟然是"return of swap is 1  x=1,y=0",输出的x和y的值并无改变!ide

缘由在于C语言函数参数的处理是从右到左的压栈顺序(这个我在看第一个代码时还不知道,由于第一个代码从左往右操做的话,结果正好符合预期),但也跟编译器有关(这个下面再说)。函数

此时的①理解时:先处理y,y为0将0压入栈,再处理x,x为1将1压入栈内,最后处理swap,值为1将1压入栈内,因此输出的是110。post

但我以后又浏览到了有关自增自减与printf的问题,url

#include <stdio.h>
int main()
{
    int x;
    x=1;
    printf("%d %d\n",x,x++);  
    x=1;
    printf("%d %d\n",x++,x);  
    x=1;
    printf("%d %d %d\n",x,x++,x);  
    x=1;
    printf("%d %d %d %d\n",x,++x,x++,x);
    return 0;
}

 

按照①理解得出的答案应该是:spa

2 1.net

1 1指针

2 1 1code

3 3 1 1htm

但GCC编译下来的结果是

2 1  

1 2  

2 1 2  

3 3 1 3

为何要特指GCC下的结果呢,由于在后来的浏览中,发现,不一样的编译器会得出不一样的结果(在第一个网页里有人就贴出了第一个代码在vc6.0下的结果,没重视,后来不断有这类的信息出现,本身重装了VC6.0才发现还真是不同!)。

在VC6.0下的:

1 1
1 1
1 1 1
2 2 1 1

这更邪乎了,在vc6.0里后置符在printf里都无论用了。

通过查阅得知,在GCC下,是先处理好全部参数,而后push,在遇到后置符时会当即输出此时的值。

而VC6.0是处理好一个参数push一个且后置符在整条printf完成后才会+1。

以这条为例

x=1;
printf("%d %d %d %d\n",x,++x,x++,x);

 GCC下:

  处理x,此时x为1。

  处理x++:temp = x, x = x + 1此时x为2,temp为1

  处理++x:x = x + 1,此时x为3

  处理x,此时x为3

  将x,temp,x,x压入栈,而后一次弹出。结果为3 3 1 3。但若是前置符是表达式中的一部分的话,则会输出此时的值进行计算,例如:++x, ++x + 3,x(x初值是1)则输出的是3 5 1而不是3  6 1

在VC6.0下:

  处理x,此时x为1,压栈。

  处理x++,此时x为1,压栈。

  处理++x,此时x为2,压栈。

  处理x,此时x为2,压栈。

  依次弹出,输出结果为2 2 1 1,而后处理x++,此时x为3,即在后面加printf输出x的值会输出3。

但又有问题了,按照GCC的方式,则printf("return of swap is %d\tx=%d,y=%d\n",swap(&x,&y),x,y)因该是1 0 1啊,为何x 和 y的值没有换呢,难道是由于指针?

并且我又发如今进行指针处理后,以后在prinf中只有在该变量自增自减处理以后的才遵照上面GCC的操做,而在该变量自增自减处理以前的该变量则输出当时的值。如:

#include <stdio.h>
int swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    return 1;
}

int main()
{
    int x = 1, y = 1;
    printf("x = %d, y = %d\n", x, y);
    swap(&x, &y);
    printf("%d %d %d\n", x, ++x, x);
      return 0;
}

 

照着上面GCC的处理,则printf("%d %d %d\n", x, ++x, x)应输出同样的值2 2 2,但实际在GCC编译后输出的值是2 2 1。

我是完全搞混了,但最终的结论是:这跟编译器如何处理有关(有人说是C/C++中未定义的行为,因此不一样编译器有不一样的操做),且在实际中不该该写出这样的代码,重点是知道C中函数参数是从右到左的压栈顺序和自增自减是如何操做。

 

参考文章链接:

C语言的陷阱:关于函数参数的“反作用”问题

C语言初探 之 printf压栈顺序(printf("%d %d %d %d %d %d\n",a++, ++a, a++, ++a, a++, ++a ))

写给初学者的有关printf("%d,%d,%d,%d\n", ++a,a++,--aa--);之类的表述

i++和++i做为参数时的编译器处理方式分析~

C语言诡异的printf函数