我无法理解以下宏:
#define CUBE(x) ((x)*(x)*(x))
我的代码:
int y=5;
print("Cube = %d",CUBE(++y));
这段代码打印512(使用Microsoft Visual Studio)
我希望打印出来:((++5)*(++6)*(++7)) = (6*7*8) = 336
如何评估?
同样的代码是使用Dev C ++编译器编译的,结果是392 !!!
有人可以解释为什么两个编译器对完全相同的代码显示不同的结果吗?
这个++y
是如何评估的?
答案 0 :(得分:3)
当宏被扩展时,y
的值被多次修改而没有中间序列点
这是未定义的行为。
未定义的行为意味着任何行为都是可能的,您的程序不是有效的c程序 因此,您可以在不同的编译器上看到不同的输出。
答案 1 :(得分:1)
CUBE(++ Y));变成(++ y * ++ y * ++ y) - 在?
中评估的顺序是什么技术性 - 在功能点之间改变相同的变量是未定义的
编辑:请参阅Undefined behavior and sequence points
Visual C ++似乎将此评估为y+=3; y*y*y; so 8*8*8 = 512
382是7 * 7 * 8所以Dev C ++可能会将第一部分评估为y+=2; y*y;
然后49*y++
答案 2 :(得分:1)
表达式中没有sequence points,因此副作用(即递增y
的结果)变得可见的时间未定义。简而言之,编译器可以在表达式的求值完成之前随时将++y
的结果存储回y
。
这就是制作带有副作用的表达式的宏的危险。使用等效函数你会好得多。
答案 3 :(得分:0)
预编译器评估此宏
#define CUBE(x) ((x)*(x)*(x))
你的代码中的:
int y=5;
print("Cube = %d",CUBE(++y));
到
int y=5;
print("Cube = %d",((++y)*(++y)*(++y)));
编写此类代码令人困惑,结果未定义。
不同的编译器可能表现不同。
避免使用此类构造,您不会遇到此类问题。
答案 4 :(得分:0)
我们需要查看代码的ASM(汇编)(gcc -S .c)才能知道它到底发生了什么。
在Dev C ++编译器中,ASM看起来像
1) movl $5, 28(%esp)
2) addl $1, 28(%esp)
3) addl $1, 28(%esp)
4) movl 28(%esp), %eax
5) imull 28(%esp), %eax
6) addl $1, 28(%esp)
7) imull 28(%esp), %eax
它显示值5被移动到%esp(1)然后在那里加上两次(2& 3),所以现在y的值变为7;此值现在移至eax寄存器(4)并乘以7 * 7(5);现在将值1添加到值y(6),然后乘以eax;所以答案是7 * 7 * 8 = 392
在Microsoft visual studio中它将是8 * 8 * 8。