可能重复:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
我现在正在上讲课,而我的讲师提到的表达方式如下:
int a , b;
a = 4;
b = a++ + a--;
我的讲师说这个表达式值可以定义:它是8.这意味着值4被求和并在它递增和递减之前分配给b。
但是对我而言,我认为这个表达式的答案有点模糊,结果将基于编译器实现。这是因为对我来说,编译器可能首先执行a ++部分 - 也就是说,使用值4并将a增加到5,之后表达式为4 + 5 = 9并且分配给b然后只减少a。
它也可能首先使用值4来执行a--部分,然后将其递减1到3,然后将值4与3相加并将值赋值给b然后仅将a递增回4。
我的问题是谁是对的,我的讲师还是我?因为我不想与它混淆,后来对我来说将是一个问题。
答案 0 :(得分:9)
你的讲师错了。在没有插入序列点的情况下写入相同的变量两次是未定义的行为。来自spec, J.2未定义的行为:
在两个序列点之间,对象被多次修改,或者被修改,并且读取先前值而不是确定要存储的值(6.5)。
引用的是 6.5表达式,第5段:
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算修改一次。此外,先前的值应该是只读的,以确定要存储的值。
C规范的附录C有一个方便的所有序列点列表:
以下是5.1.2.3中描述的序列点:
- 在评估参数(6.5.2.2)之后调用函数。
- 以下运算符的第一个操作数的结尾:逻辑AND
&&
(6.5.13);逻辑OR||
(6.5.14);条件?
(6.5.15);逗号,
(6.5.17)。- 完整声明者的结尾:声明者(6.7.5);
- 完整表达式的结束:初始化程序(6.7.8);表达式中的表达式(6.8.3);选择语句的控制表达式(
if
或switch
)(6.8.4);控制表达while
或do
声明(6.8.5);for
语句的每个表达式(6.8.5.3);return
语句(6.8.6.4)中的表达式。- 在库函数返回之前(7.1.4)。
- 与每个格式化输入/输出函数转换说明符(7.19.6,7.24.2)相关联的操作之后。
- 在每次调用比较函数之前和之后,以及对比较函数的任何调用和作为参数传递给对象的任何移动之间(7.20.5)。