我在c
中写了以下代码int x = 8;
x -= --x - x--;
printf("%d", x);
它是打印6但是根据我的逻辑语句应该转换为(从右到左执行)
x = 6-6-8;
所以答案应该是-8。
有谁可以说这里发生了什么?
答案 0 :(得分:3)
这是未定义的行为。 C99标准§6.5¶2说
在前一个和下一个序列点之间,一个对象应该具有它 通过表达式的评估,最多修改一次存储值。 此外,先前的值应只读以确定该值 存储。
x -= --x - x--;
// equivalent to
x = x - --x - x--;
// postfix decrement has higher precedence than
// prefix decrement. Both have higher precedence than
// subtraction operator. Therefore the above statement is
// equivalent to
x = x - (--x) - (x--);
// the subtraction associates from left to right
// therefore the above statement is parsed as
x = (x - (--x)) - (x--);
现在,需要注意的重要一点是-
运算符的操作数的评估相对于彼此是无序的。这意味着不会修复哪个子表达式(x - (--x))
或(x--)
将首先进行评估。
C中没有从左到右或从右到左评估的概念, 不要混淆从左到右和从右到左 运算符的关联性:表达式a + b + c被解析为(a + b)+ c由于操作符+从左到右的相关性,但是 可以首先(或最后,或同时)评估子表达式c 作为a或b)在运行时。
要注意的第二个重要事项是,在上述声明中,由于表达式x
和--x
的副作用,x--
的值被修改了两次。这两个表达式的评估之间没有序列点,因此在发生副作用时无法保证。因此,参考标准中的上述部分,它是未定义的行为。
结合上述两个陈述的点,表达式可以评估为多个值。
int x = 8;
x = (x - (--x)) - (x--);
// (a) (b) (c) name of the sub expressions
// assume (c) is evaluated first and side effect
// takes place immediately. Then (b) is evaluated and
// side effect takes place immediately
x = (6 - (6)) - (8); // -8
// assume (a) is evaluated first, then (b)
// however the side effect of (b) does not take
// place before (c) gets evaluated
x = (8 - (7)) - (7); // -6
这些只是两个例子来说明执行语句后x
可以有的不同值。这不应被视为x
将始终具有所有可能值中的一个值。标准说它是未定义的行为,这意味着行为是不可预测的。该标准对处理此类案件的实施没有要求。未定义的行为意味着任何事情都可能发生在从您的鼻子飞到您的硬盘驱动器格式化的守护进程。您应该始终避免编写调用未定义行为的代码。有关详细信息,请阅读此内容 - Undefined Behavior and Sequence Points。