zoukankan      html  css  js  c++  java
  • C: printf参数执行顺序与前置后置自增自减的影响

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

     

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

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

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

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

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

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

    2 1

    1 1

    2 1 1

    3 3 1 1

    但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
    ",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 x=%d,y=%d ",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
    ", x, y);
        swap(&x, &y);
        printf("%d %d %d
    ", x, ++x, x);
          return 0;
    }

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

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

    参考文章连接:

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

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

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

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

    C语言诡异的printf函数

     
  • 相关阅读:
    artDialog组件应用学习(二)
    artDialog组件应用学习(一)
    MVC Request.UrlReferrer为null
    jquery的toggle()方法
    Windows 和 Linux 下生成以当前时间命名的文件
    再提供一种解决Nginx文件类型错误解析漏洞的方法
    Nginx 1.5.2 + PHP 5.5.1 + MySQL 5.6.10 在 CentOS 下的编译安装
    架构师对话
    Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建胜过Apache十倍的Web服务器
    Nginx 0.7.x + PHP 5.2.6(FastCGI)+ MySQL 5.1 在128M小内存VPS服务器上的配置优化
  • 原文地址:https://www.cnblogs.com/Will-zyq/p/10293344.html
Copyright © 2011-2022 走看看