正在同时修改指向的值和指针 UB
Is modifying the pointed value and the pointer at the same time UB
我知道 C 和 C++ 以及不同的语言,但以下内容适用于两者。
TL/DR
我知道i = i++;
是UB,因为i在表达式中修改了两次,C和C++禁止它。
参考文献:
C99 6.5 :
If a side effect on a scalar object is unsequenced relative to either a different side effect
on the same scalar object or a value computation using the value of the same scalar
object, the behavior is undefined. If there are multiple allowable orderings of the
subexpressions of an expression, the behavior is undefined if such an unsequenced side
effect occurs in any of the orderings
C++ 11 - 1.9 15 :
If a side effect on a scalar
object is unsequenced relative to either another side effect on the same scalar object or a value computation
using the value of the same scalar object, and they are not potentially concurrent, the behavior is
undefined.
所以我理解 *i = *i++ + *j++;
导致 UB,因为 post 在 i
上的增量和对 *i
的影响可能是未排序的,并且 CLang 在 C 或C++ 模式:警告:未排序的修改和访问 'i' [-Wunsequenced] *i = *i++ + *j++;
但我不理解 *i++ = *i + *j++;
上的相同警告。因为这里,我们先计算右边的部分,影响它,影响后自增。
两种语言的规格说明(同一段,就在上面):
The value computations of the operands of an operator
are sequenced before the value computation of the result of the operator
结束TL/DR
所以问题是:
是这条线吗
*i++ = *i + *j++;
未定义的行为,或者 Clang(版本 3.4.1)在发出警告方面过于保守?
两者的原因
*i = *i++ + *j++;
和
*i++ = *i + *j++;
are undefined 是您试图在表达式中使用指针 i
,该表达式是值计算(取消引用,*i
)和具有副作用的表达式(取消引用和递增,*i++
) 没有中间序列点。请记住 *i++
被评估为 *(i++)
;你增加的是指针值,而不是被指向的东西。
给定 x = *i + *i++;
将子表达式 i++
分解为七个部分是合法的:
- 捕获表达式 *i++ 部分的指针状态
- 读取那个地址
- 捕获表达式 *i 部分的指针状态
- 读取那个地址
- 将读取的两个值相加
- 将结果存储在 X 中。
- 将指针置于无效状态(例如,对于大于
int
的指针,从递增下半部分开始,这可能会回绕)
- 将指针置于标识下一个对象的有效状态(完成写入更新的指针值)
步骤#1 必须在前面,并且必须在#7 之前,而#7 又必须在#8 之前,但编译器可能会重新排列任何或所有操作#2-#6,以便它们发生在之前、之后或之后在#7 和#8 之间。标准中的任何内容都不需要编译器做出任何努力来确保对同一指针的所有其他访问将发生在#7 之前或#8 之后;如果编译器碰巧在步骤#7 和#8 之间放置了不同的访问权限,则无法说明使用临时无效指针的后果可能是什么。
我知道 C 和 C++ 以及不同的语言,但以下内容适用于两者。
TL/DR
我知道i = i++;
是UB,因为i在表达式中修改了两次,C和C++禁止它。
参考文献:
C99 6.5 :
If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings
C++ 11 - 1.9 15 :
If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined.
所以我理解 *i = *i++ + *j++;
导致 UB,因为 post 在 i
上的增量和对 *i
的影响可能是未排序的,并且 CLang 在 C 或C++ 模式:警告:未排序的修改和访问 'i' [-Wunsequenced] *i = *i++ + *j++;
但我不理解 *i++ = *i + *j++;
上的相同警告。因为这里,我们先计算右边的部分,影响它,影响后自增。
两种语言的规格说明(同一段,就在上面):
The value computations of the operands of an operator are sequenced before the value computation of the result of the operator
结束TL/DR
所以问题是:
是这条线吗
*i++ = *i + *j++;
未定义的行为,或者 Clang(版本 3.4.1)在发出警告方面过于保守?
两者的原因
*i = *i++ + *j++;
和
*i++ = *i + *j++;
are undefined 是您试图在表达式中使用指针 i
,该表达式是值计算(取消引用,*i
)和具有副作用的表达式(取消引用和递增,*i++
) 没有中间序列点。请记住 *i++
被评估为 *(i++)
;你增加的是指针值,而不是被指向的东西。
给定 x = *i + *i++;
将子表达式 i++
分解为七个部分是合法的:
- 捕获表达式 *i++ 部分的指针状态
- 读取那个地址
- 捕获表达式 *i 部分的指针状态
- 读取那个地址
- 将读取的两个值相加
- 将结果存储在 X 中。
- 将指针置于无效状态(例如,对于大于
int
的指针,从递增下半部分开始,这可能会回绕) - 将指针置于标识下一个对象的有效状态(完成写入更新的指针值)
步骤#1 必须在前面,并且必须在#7 之前,而#7 又必须在#8 之前,但编译器可能会重新排列任何或所有操作#2-#6,以便它们发生在之前、之后或之后在#7 和#8 之间。标准中的任何内容都不需要编译器做出任何努力来确保对同一指针的所有其他访问将发生在#7 之前或#8 之后;如果编译器碰巧在步骤#7 和#8 之间放置了不同的访问权限,则无法说明使用临时无效指针的后果可能是什么。