小脑斧 发表于 2019-7-6 19:59:09

关于宏定义参数是i++情况,vs与devc++结果不一样呢?

本帖最后由 小脑斧 于 2019-7-6 20:41 编辑

小甲鱼:课堂中留下的问题,请问下面宏定义隐藏着一个难以发现的 BUG,是处理宏定义的参数遇到 ++、-- 运算符的时候,我分别在vs2012和devc++运行,结果不一样,这是为啥呢

运行代码:
#include <stdio.h>

#define SQUARE(x) ((x) * (x))

int main(void)
{
      int i = 1;

      while (i <= 5)
      {
                printf("%d 的平方是%d\n", i-1, SQUARE(i++));
      }

      return 0;
}

vs运行结果如下:




dev结果如下:



小甲鱼的结果和vs一样




人造人 发表于 2019-7-6 20:24:23

printf("%d 的平方是%d\n", i-1, SQUARE(i++));
相当于
printf("%d 的平方是%d\n", i-1, ((i++) * (i++)));

小脑斧 发表于 2019-7-6 20:34:27

人造人 发表于 2019-7-6 20:24
相当于

我知道是这个式子,vs的结果图没传上来,两个软件结果不一样,,,,
桌面

小脑斧 发表于 2019-7-6 20:38:33

人造人 发表于 2019-7-6 20:24
相当于

D:\

小脑斧 发表于 2019-7-6 20:39:29


小脑斧 发表于 2019-7-6 20:44:10

人造人 发表于 2019-7-6 20:24
相当于

刚刚没传上图片,终于成功了

人造人 发表于 2019-7-6 20:53:26

printf("%d 的平方是%d\n", i-1, ((i++) * (i++)));

也就是说,你现在的问题是:为什么这行代码用不同的编译器结果不同
是这样吧

小脑斧 发表于 2019-7-6 20:59:43

人造人 发表于 2019-7-6 20:53
也就是说,你现在的问题是:为什么这行代码用不同的编译器结果不同
是这样吧

是滴

人造人 发表于 2019-7-6 21:20:22

小脑斧 发表于 2019-7-6 20:59
是滴

printf("%d 的平方是%d\n", i-1, ((i++) * (i++)));

如果你是编译器,当你看到这样的代码时会怎么做?

如果我是编译器,我会有几个问题
1. 我是应该先计算 i - 1还是先计算((i++) * (i++)) ?
2. 当我计算((i++) * (i++))的时候,应该怎么算?
例如 i 是5
乘法运算需要两个数,a * b = c
我需要把((i++) * (i++))带进公式,计算出c
问题是a和b应该是多少?

(1)
a = 5
b = 5
a和b全是5,两个++运算都在计算乘法之后

(2)
a = 5
b = 6
a是5,但是读取b的时候i已经++,现在b读取到的是6

(3)
a = 6
b = 5
这个的问题也一样,不过这个是先读取b,然后++,然后读取a


既然我有这些问题,编译器也会有这些问题,不同的编译器有不同的处理方法,也就是不同的编译器有不同的结果
这样的代码不符合标准,不同的编译器会有不同的计算方法

人造人 发表于 2019-7-6 21:34:44

好像还有好多算法,我不想继续了,^_^

int i = 5;
printf("%d 的平方是%d\n", i-1, ((i++) * (i++)));

算法1
int temp1, temp2, temp3, temp4;
temp3 = i;                // temp3 = 5
temp4 = i;                // temp4 = 5
temp2 = temp3 * temp4;        // temp2 = 25
i = i + 1;                // i = 6
i = i + 1;                // i = 7
temp1 = i - 1;                // temp1 = 6
printf("%d 的平方是%d\n", temp1, temp2);        // temp1 = 6, temp2 = 25

算法2
int temp1, temp2, temp3, temp4;
temp3 = i;                // temp3 = 5
i = i + 1;                // i = 6
temp4 = i;                // temp4 = 6
i = i + 1;                // i = 7
temp2 = temp3 * temp4;        // temp2 = 30
temp1 = i - 1;                // temp1 = 6
printf("%d 的平方是%d\n", temp1, temp2);        // temp1 = 6, temp2 = 30

算法3
int temp1, temp2, temp3, temp4;
temp1 = i - 1;                // temp1 = 4
temp3 = i;                // temp3 = 5
i = i + 1;                // i = 6
temp4 = i;                // temp4 = 6
i = i + 1;                // i = 7
temp2 = temp3 * temp4;        // temp2 = 30
printf("%d 的平方是%d\n", temp1, temp2);        // temp1 = 4, temp2 = 30

算法4
int temp1, temp2, temp3, temp4;
temp1 = i - 1;                // temp1 = 4
temp3 = i;                // temp3 = 5
temp4 = i;                // temp4 = 5
temp2 = temp3 * temp4;        // temp2 = 25
i = i + 1;                // i = 6
i = i + 1;                // i = 7
printf("%d 的平方是%d\n", temp1, temp2);        // temp1 = 4, temp2 = 25

小脑斧 发表于 2019-7-7 08:35:41

人造人 发表于 2019-7-6 21:20
如果你是编译器,当你看到这样的代码时会怎么做?

如果我是编译器,我会有几个问题


理解了,小甲鱼后来是按先读取i++后读取i-1的顺序讲的:函数参数调用进栈的顺序是右边先进入所以gcc的结果和vs的一致,dev可能就是不一样,总之结果都不对就是了{:5_91:}

小脑斧 发表于 2019-7-7 08:37:14

人造人 发表于 2019-7-6 21:34
好像还有好多算法,我不想继续了,^_^

太感谢了{:5_92:}{:5_106:}

我就是个弟弟 发表于 2019-7-7 12:37:45

这是C语言标准未定义的行为,说白了就是要看编译器。
页: [1]
查看完整版本: 关于宏定义参数是i++情况,vs与devc++结果不一样呢?