我知道C和C ++以及不同的语言,但以下内容适用于这两种语言。
TL / DR
我知道i = i++;
是UB,因为我在表达式中修改了两次,C和C ++禁止它。
参考文献:
C99 6.5:
如果相对于不同的副作用,对标量对象的副作用未被排序 在相同的标量对象上或使用相同标量的值进行值计算 对象,行为未定义。如果有多个允许的排序 表达式的子表达式,如果这样一个未经测序的一方,则行为是不确定的 效果发生在任何排序
C ++ 11 - 1.9 15:
如果对标量有副作用 对于相同标量对象的另一个副作用或值计算,对象未被排序 使用相同标量对象的值,并且它们不可能并发,行为是 未定义。
所以我理解*i = *i++ + *j++;
会导致UB,因为i
上的后增量和对*i
的影响可能没有排序,并且CLang在C或C ++模式下发出警告:警告:未经测试的修改和访问'i'[-Wunsequenced] *i = *i++ + *j++;
但我对*i++ = *i + *j++;
的同样警告并不理解。因为在这里,我们首先计算正确的部分,影响它,并在做作后增加。
两种语言的规格都说(同一段,上面):
运算符的操作数的值计算 在运算符结果的值计算之前进行排序
END TL / DR
所以问题是:
这一行
*i++ = *i + *j++;
未定义的行为,或Clang(版本3.4.1)在发出警告时过于保守?
答案 0 :(得分:2)
两个原因
*i = *i++ + *j++;
和
*i++ = *i + *j++;
未定义的是您尝试在表达式中使用指针i
,该表达式是一个值计算(取消引用,*i
)和一个带副作用的表达式(取消引用和增量, *i++
)没有插入序列点。请记住,*i++
评估为*(i++)
;你正在递增指针值,而不是指向的东西。
答案 1 :(得分:1)
鉴于x = *i + *i++;
,将子表达式i++
分解为七个部分是合法的:
int
的指针,首先递增下半部分,这可能会换行)步骤#1必须是第一个,并且必须在#7之前,而#7必须先于#8,但编译器可以重新排列任何或所有操作#2-#6,以便它们在#之前,之后或之间发生# 7和#8。标准中的任何内容都不需要编译器做出任何努力来确保对#17之前或#8之后的同一指针的所有其他访问;如果编译器碰巧在步骤#7和#8之间进行了不同的访问,则无法确定使用临时无效指针的后果是什么。