评估宏

可能重复:
未定义的行为和序列点

我无法理解以下宏:

#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如何评估?

当宏被扩展时, y的值被多次修改而没有中间序列点。
这是未定义的行为

未定义的行为意味着任何行为都是可能的,您的程序不是有效的c程序。
因此,您在不同的编译器上看到不同的输出。

表达式中没有序列点 ,因此未定义副作用(即递增y的结果)变得可见的时间。 简单来说,编译器可以在表达式的求值完成之前随时将++y的结果存储回y中。

这是制作带有副作用的表达式的宏的危险。 使用等效function会更好。

CUBE(++ Y)); 变成(++ y * ++ y * ++ y) – 评估的顺序是什么?

要技术性 – 在function点之间改变相同的变量是不明确的

编辑:请参阅未定义的行为和序列点

Visual C ++似乎将其评估为y+=3; y*y*y; so 8*8*8 = 512 y+=3; y*y*y; so 8*8*8 = 512
382是7 * 7 * 8所以Dev C ++可能会将第一部分评估为y+=2; y*y; y+=2; y*y; 那么49*y++

预编译器评估此宏

 #define CUBE(x) ((x)*(x)*(x)) 

在你的代码中:

 int y=5; print("Cube = %d",CUBE(++y)); 

 int y=5; print("Cube = %d",((++y)*(++y)*(++y))); 

编写此类代码令人困惑,结果未定义。

不同的编译器可以表现不同。

避免使用这种结构,你不会遇到这样的问题。

我们需要查看代码的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。