2

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

我无法理解以下宏:

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

4

5 回答 5

3

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

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

于 2012-06-08T17:23:25.717 回答
1

立方体(++y));变为 (++y * ++y * ++y) - 评估的顺序是什么?

从技术上讲-在功能点之间更改相同的变量是未定义的

编辑:见未定义的行为和序列点

Visual C++ 似乎将此评估为y+=3; y*y*y; so 8*8*8 = 512
382 是 7*7*8 所以 Dev C++ 大概评估第一部分为y+=2; y*y; then49*y++

于 2012-06-08T17:21:58.250 回答
1

您的表达式中没有序列点,因此副作用(即递增的结果y)变得可见的时间是不确定的。简而言之,编译器可以在表达式计算完成之前的任何时间将结果存储++y回。y

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

于 2012-06-08T17:22:46.697 回答
0

预编译器评估此宏

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

在您的代码中:

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

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

编写这样的代码是令人困惑的,结果是不确定的。

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

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

于 2012-06-08T17:24:43.267 回答
0

我们需要查看代码 (gcc -S .c) 的 ASM(汇编)来了解它到底发生了什么。

在 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);现在将值 y (6) 加 1,然后与 eax 相乘;所以答案是 7 * 7 * 8 = 392

在 Microsoft Visual Studio 中,它将是 8 * 8 * 8。

于 2012-06-08T17:58:04.260 回答