【问题标题】:C++ is it legal to take the address of 2 or more past the end of the array?C++ 在数组末尾取 2 个或更多的地址是否合法?
【发布时间】:2014-01-01 22:32:56
【问题描述】:

来自Take the address of a one-past-the-end array element via subscript: legal by the C++ Standard or not?

似乎有特定的语言可以将一个的地址多于一个数组结尾。

如果没有取消引用,为什么 22,000,000 会成为问题?

看一些简单的循环:

int array[];
...
for (int i = 0: i < array_max; ++i)
{
       int * x = &array[i *2];      // Is this legal
       int y=0;
       if (i * 2 < array_max)       // We check here before dereference
       {
              y = *x;               // Legal dereference
       }
       ...
}

为什么或在什么时候它变得未定义,实际上它只是将一个 ptr 设置为某个值,如果它没有被引用,为什么它会是未定义的?

更具体地说 - 除了预期会发生什么之外,还有什么例子?

【问题讨论】:

  • 有一个指针指向UB。
  • 不,这是不合法的。即使它应该工作。
  • 因为它在比较或减法方面可能表现不佳。例如(p + 2000000000) - p 可能不等于 2000000000。
  • @RaymondChen - 在这个例子中,除了赋值和限定解引用之外什么都没有 - 该值仅在验证后使用,问题是为什么值的设置有问题?
  • 是否只是有一个指向未定义数组末尾 2 的指针,而没有取消引用或添加它?

标签: c++ arrays


【解决方案1】:

使用超出数组末尾的地址的关键问题是分段架构:您可能会溢出指针的可表示范围。现有规则已经造成了一定程度的痛苦,因为这意味着最后一个对象不能正好位于段的边界上。然而,形成这个地址的能力已经很成熟了。

【讨论】:

  • 为什么即使没有取消引用也会出现问题?
  • @LightnessRacesinOrbit:这些并不能解释为什么“对象结束”指针越过段边界是一个问题。
  • @zneak:使用分段指针,指针比较是在单个段中完成的。如果一个对象在段边界上结束,它后面的指针不指向同一个段,因此无法比较。
【解决方案2】:

由于array[i *2] 等价于*((array) + (i*2)),我们应该看看指针加法的规则。 C++11 §5.7 说:

如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不应产生溢出;否则,行为未定义。

因此,即使您不对指针执行间接操作,您也有未定义的行为(更不用说您确实执行了间接操作,因为我在开头给出了表达式等价)。

【讨论】:

  • 我认为在新的 C++11 规则下,两个表达式都不执行间接操作。它们既不是读也不是写。
  • @MSalters:为什么?
  • @LightnessRacesinOrbit IIRC 使&amp;array[last]合法化
  • @MSalters:是的,这就是您评论的答案中的引文所说的,不是吗?关键是这个问题是关于&amp;array[last+1],而不是&amp;array[last]
  • @LightnessRacesinOrbit:完全意识到这一点,但关键是你的最后一句话假设间接发生,两种形式。我的声明是两种语法都不执行间接操作。它们都只是形成一个地址,只有后续使用指定对象才可能触发间接寻址。
【解决方案3】:

实际上,它只是将 ptr 设置为某个值

理论上,不允许仅使用指向无效位置的指针。

指针不是整数:它们是指向其他事物或空值的事物。

您不能将它们设置为您喜欢的任何数字。

在这个例子中,除了赋值和限定解引用之外什么都没有——该值仅在验证后使用,问题是为什么值的设置有问题?

是的,你必须非常不幸地遇到这样做的实际后果。 “未定义的行为”不是意味着“总是崩溃”。为什么标准实际上要为这样的操作规定语义?你认为这样的语义应该是什么?

【讨论】:

  • 但是你可以将它们转换为一个整数(或者更确切地说是 uintptr_t),对它们做任何你想做的事情并将它们转换回来(如果它们是有效的)。
  • @user2345215:是的,就像您可以使用reinterpret_cast 将它们投射到ChickenSoup* 一样。这不会改变它们的意图,这是规则所依据的。
猜你喜欢
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 2021-02-07
  • 1970-01-01
  • 1970-01-01
  • 2011-02-21
相关资源
最近更新 更多