在同一时间修改指向的值和指针UB

我知道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 ++模式下发出警告:warning:无序修改和访问'i'[-Wunsequenced] *i = *i++ + *j++;

但我不明白*i++ = *i + *j++;上的警告*i++ = *i + *j++; 。 因为在这里,我们首先计算正确的部分,影响它,然后在情感化之后增加。

这两种语言的规格说(相同的段落,就在上面):

运算符操作数的值计算在运算符结果的值计算之前排序

END TL / DR

所以问题是:

是这条线

*i++ = *i + *j++;

未定义的行为,还是Clang(版本3.4.1)在发布警告时过于保守?


两者的原因

*i = *i++ + *j++;

*i++ = *i + *j++;

未定义的是你试图在一个表达式中使用指针i ,这个表达式是一个值计算(dereference, *i )和一个带有副作用的表达式(取消引用和增量, *i++ ),没有中间顺序点。 记住*i++被评估为*(i++) ; 你正在增加指针值,而不是指向的东西。


给定x = *i + *i++; 将子表达式i++分解成七部分将是合法的:

  • 捕获表达式的* i ++部分的指针状态
  • 阅读该地址
  • 捕获表达式* i部分的指针状态
  • 阅读该地址
  • 添加读取的两个值
  • 将结果存储在X.
  • 将指针置于无效状态(例如,对于大于int指针,从下半部分开始,可能会换行)
  • 将指针置于标识下一个对象的有效状态(完成写入更新的指针值)
  • 步骤#1必须是第一个,并且必须在#7之前,其必须在#8之前,但是编译器可以重新布置任何或全部操作#2-#6,以使它们发生在#7和#之前,之后或之间, 8。 标准中的任何内容都不需要编译器做出任何努力来确保对同一指针的所有其他访问将在#7之前或#8之后发生; 如果编译器碰巧在步骤#7和#8之间设置了不同的访问权限,则不知道使用临时无效指针的后果可能是什么。

    链接地址: http://www.djcxy.com/p/73219.html

    上一篇: Is modifying the pointed value and the pointer at the same time UB

    下一篇: Assignment operator sequencing in C11 expressions