【问题标题】:Is incrementing/decrementing or adding an integer value to a pointer that is not pointing to an element in a sequence Undefined Behavior?是否对未指向序列中元素的指针进行递增/递减或添加整数值未定义行为?
【发布时间】:2020-12-06 19:46:08
【问题描述】:

我知道指针(指向数组元素)和迭代器可以递增/递减以遍历一系列元素,并且可以在序列中来回跳转。

但是如果我增加一个指向单个对象的指针或添加一个整数值会发生什么?是未定义的行为还是可以但我们无法访问该内存?

int x = 551;
int* p = &x;
++p;
--p;
std::cout << *p << '\n';

因为我已经读过,我们不应该增加/减少不指向序列或数组中元素的指针。

那么有人可以解释会发生什么以及我的示例是否可以(取消引用指针 p)?谢谢!

【问题讨论】:

  • 这是一个非常好的问题,因为编译器编写者越来越积极地利用未定义的行为规则,并且当您不小心绊倒极端情况时,会使代码产生完全不可预测的后果。
  • 这不是一个很好的副本。它甚至没有涉及减法的情况,本来可以合理地(但实际上没有)以不同的方式处理。
  • @AsteroidsWithWings 是的,这很合理。这比另一个更一般。我会调整目标方向,谢谢。

标签: c++ pointers language-lawyer pointer-arithmetic


【解决方案1】:

当指针算法应用于指向对象的指针时,该指针被视为指向该对象类型的数组,该数组只有一个元素,如standard 中所述。

为了这个目的,一个不是数组元素的对象被认为属于一个单元素数组

在你的例子中,指针p 好像它指向int arr[1] = {551} 因此,相应的操作类似于应用于指向arr 的指针。这意味着,++p 将使p 指向元素 arr[1](假设),--p 将使p 再次指向第一个元素 arr[0]。因此,最后,取消引用指针 p 是可以的,不会导致任何 UB。

【讨论】:

    【解决方案2】:

    总结

    您的程序没有定义明确,甚至在取消引用之前也是如此。

    • 您可以将p 增加一次,从而产生一个过去的指针
    • 但是,您不能减少一个过去的指针

    标准

    标准中与此功能相关的规则are given in terms of arrays,但a note reminds us 出于这些目的,单个对象被视为单个元素数组的元素,引用以下段落描述了您的含义指针:

    [basic.compound/3]: [..] 指针类型的值是指向或超过对象末尾的指针,表示内存中第一个字节的地址([intro.memory ]) 对象占用的存储空间结束后的内存中的第 46 个字节或对象占用的内存中的第一个字节。 [..] 用于指针算术 ([expr.add]) 和比较 ([expr.rel], [expr.eq]), a超过 n 个元素的数组 x 的最后一个元素末尾的指针被认为等同于指向 x 的假设数组元素 n 的指针,并且一个不是数组元素的T 类型的对象被认为属于一个具有一个T 类型元素的数组。 [..]

    所以,是的,您可以按照这些规则安全地“获取”过去的指针。不幸的是,你不能对它做太多事情,因为指针加减规则是这样定义的:

    [expr.add/4]:当指针类型的表达式P加上或减去整数类型的表达式J时,结果的类型为P

    • 如果P 的计算结果为空指针值,而J 的计算结果为0,则结果为空指针值。
    • 否则,如果P 指向数组对象x 的数组元素i,其中n 个元素([dcl. array]),80 表达式P + JJ + P(其中J 的值为j)指向x 的(可能是假设的)数组元素i+j if 0≤i+j≤n 并且表达式P - J 指向x 的(可能是假设的)数组元素i−j if 0 ≤i−j≤n.
    • 否则,行为未定义。

    …而&amp;x+1 甚至不是对象x 所呈现的组合数组的元素。

    如果它说 “如果 P 指向带有 n 个元素的数组对象 x 的(可能是假设的)数组元素 i 那么你就可以了,因为这会扩展第二个项目符号中给出的行为以覆盖过去的指针(这是第一个“x 的假设数组元素”引用)。但事实并非如此,所以我们进入第三个要点,让您的程序具有未定义的行为。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 1970-01-01
    • 2014-06-10
    • 1970-01-01
    • 2021-03-04
    • 1970-01-01
    相关资源
    最近更新 更多