鱼C论坛

 找回密码
 立即注册
查看: 2428|回复: 12

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

[复制链接]
发表于 2019-7-6 19:59:09 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 小脑斧 于 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运行结果如下:
是.png



dev结果如下:
分.png


小甲鱼的结果和vs一样




最佳答案
2019-7-6 21:20:22
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


既然我有这些问题,编译器也会有这些问题,不同的编译器有不同的处理方法,也就是不同的编译器有不同的结果
这样的代码不符合标准,不同的编译器会有不同的计算方法
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-7-6 20:24:23 | 显示全部楼层
printf("%d 的平方是%d\n", i-1, SQUARE(i++));
相当于
printf("%d 的平方是%d\n", i-1, ((i++) * (i++)));
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-7-6 20:34:27 | 显示全部楼层

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

                               
登录/注册后可看大图
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-7-6 20:38:33 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-7-6 20:39:29 | 显示全部楼层

是.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-7-6 20:44:10 | 显示全部楼层

刚刚没传上图片,终于成功了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-7-6 20:53:26 | 显示全部楼层
printf("%d 的平方是%d\n", i-1, ((i++) * (i++)));

也就是说,你现在的问题是:为什么这行代码用不同的编译器结果不同
是这样吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

是滴
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-7-6 21:20:22 | 显示全部楼层    本楼为最佳答案   
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


既然我有这些问题,编译器也会有这些问题,不同的编译器有不同的处理方法,也就是不同的编译器有不同的结果
这样的代码不符合标准,不同的编译器会有不同的计算方法
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-7-7 08:35:41 | 显示全部楼层
人造人 发表于 2019-7-6 21:20
如果你是编译器,当你看到这样的代码时会怎么做?

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

理解了,小甲鱼后来是按先读取i++后读取i-1的顺序讲的:函数参数调用进栈的顺序是右边先进入所以gcc的结果和vs的一致,dev可能就是不一样,总之结果都不对就是了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-7-7 08:37:14 | 显示全部楼层
人造人 发表于 2019-7-6 21:34
好像还有好多算法,我不想继续了,^_^

太感谢了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-7-7 12:37:45 | 显示全部楼层
这是C语言标准未定义的行为,说白了就是要看编译器。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-3 23:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表