同时修改指向值和指针UB
Is modifying the pointed value and the pointer at the same time UB
我知道C和c++和不同的语言,但以下内容适用于两者。
TL博士/
我知道i = i++;
是UB,因为I在表达式中被修改了两次,而C和c++禁止它。
引用:
C99 6.5:
如果标量对象上的副作用相对于另一个副作用是无序的在同一标量对象上,或使用同一标量的值进行值计算对象时,行为未定义。如果有多个允许的排序如果是表达式的子表达式,则如果有这样的未排序的一侧,则该行为是未定义的
c++ 11 - 1.9 15:
如果是标量的副作用对象相对于同一标量对象或值计算上的另一个副作用是无序的使用相同标量对象的值,并且它们不是潜在的并发,则行为是定义。
所以我理解*i = *i++ + *j++;
导致UB,因为i
的后增量和对*i
的影响可能是未排序的,CLang在C或c++模式下发出警告:警告:未排序的修改和访问' I ' [- unsequenced] *i = *i++ + *j++;
但是我不理解*i++ = *i + *j++;
上同样的警告。因为在这里,我们首先计算正确的部分,影响它,并在影响后增加。
两种语言的规范都说(同样的段落,就在上面):
操作符操作数的值计算在运算符
的结果的值计算之前排序。
结束TL博士/
所以问题是:
这行是
*i++ = *i + *j++;
未定义的行为,还是Clang(版本3.4.1)在发出警告时过于保守?
原因
*i = *i++ + *j++;
和
*i++ = *i + *j++;
是未定义的是,你试图在一个表达式中使用指针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之间放置了不同的访问,则无法告诉使用临时无效指针的后果可能是什么。
- 1d 智能指针不适用于语法 (*)++
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 为什么使用 "this" 指针调用派生成员函数?
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用指针从C++中的数组中获取最大值
- 助记符和指向成员语法的指针
- 嵌入方指针压缩已禁用
- 数组的指针从不分段故障
- 通过指针恢复对数组的引用.UB与否?
- 传递给放置 new 的指针是否是指向其对象表示形式的非 UB 指针?
- 是否通过单元化指针UB访问静态类成员
- 当原始数据是常量时,修改指针指向的位置是 UB 吗?
- 通过reinterpret_casting方法指针从指针调用派生类的方法。这是 UB 吗?
- 泛型方法指针.reinterpret_cast指向不同类的方法指针,这是 UB 吗?
- 使用指针的法律遗留代码突然变成了 UB
- 移动指针是否经过结构成员 UB?并访问它?
- 在分配的存储UB上是指针算术
- 指向成员表达式UB的指针
- 关于指针积分加法中的类型、溢出和 UB 的混淆
- 同时修改指向值和指针UB