【问题标题】:Arithmetic Pointers referencing same addresses引用相同地址的算术指针
【发布时间】:2020-02-11 20:07:33
【问题描述】:

我有点难以理解以下操作:

B是变量,Pt1和Pt2都指向&B

减量是在做作之后完成的,所以按照我的逻辑应该是 68,但我的 IDE 给了我 69,有人可以解释一下吗?

提前致谢。

【问题讨论】:

标签: c pointers assignment-operator order-of-execution


【解决方案1】:

您给出的代码会产生未定义的行为!去掉指针方面,你实际上是在这样做:

B = B--;

这无法始终如一地解决,因为您正在分配 B 的值 69然后 后递减 B。那么,这给出了答案:赋值还是后递减?

使用您的平台/IDE,编译器使用“临时”变量完成了类似的操作:

// Initial value of B is 69
temp = B--; // temp is 69 and B is now 68
B = temp;   // B now has the value of 69!

但是,您不能依赖这种“解释”——无论是跨不同的编译器,还是使用相同的编译器在不同的地方使用相似的代码!

PS:顺便说一句,您应该将代码发布为文本,格式化为代码块。

【讨论】:

  • “那么,这给出了答案:赋值还是后递减?”先评估哪个。没有办法对此进行逻辑推理,因为没有理由说明评估顺序不是确定性的,如 C++17 所示。然而,C 委员会坚持认为 C 语言必须保持中断,因此未指定顺序。你需要指出标准才能回答这个问题,你不能根据逻辑推理写出答案,因为语言不合理。
  • 话虽如此,B = B-- 这样的代码当然也不合理。
【解决方案2】:

C 标准 6.5 对这种现象给出了这种神秘的解释:

如果标量对象的副作用相对于同一标量对象的不同副作用或使用相同标量的值的值计算是无序的 对象,行为未定义。如果有多个允许的排序 表达式的子表达式,如果这样的未排序的一面,则行为未定义 效果发生在任何排序中。

  • 在这种情况下,“标量对象”是指指向的原始变量。
  • 在这种情况下,“值计算”是取消引用其中一个指针。它们指向同一个变量。
  • 在这种情况下,“副作用”是指修改变量。 = 赋值和 -- 运算符都是副作用。

赋值运算符未指定其操作数的求值顺序(6.5.16“操作数的求值未排序。”)。未指定 *Pt2 发生在 *Pt1-- 之前还是之后。

这意味着编译器必须一次更新同一个变量两次。由于这不是一个定义明确的场景,编译器可能会生成不正确的代码。可以显示奇怪值甚至崩溃的代码。这被称为未定义的行为 - 一个错误,它使您的程序处于无法再依赖确定性行为或预测任何结果的状态。

避免这种情况的简单方法是遵循以下最佳实践规则:

切勿在同一表达式中将 ++ 或 -- 运算符与其他运算符一起使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 2013-11-06
    • 1970-01-01
    • 2016-02-08
    • 1970-01-01
    相关资源
    最近更新 更多