【问题标题】:C++ Array out of Range access to calculate pointer valid?C++ 数组超出范围访问计算指针有效吗?
【发布时间】:2018-07-04 01:43:43
【问题描述】:

以下代码是否可以保证正常工作?

int* arr = new int[2];
std::cout << &arr[0x100];

这被认为是一种好的做法,还是以常规方式添加偏移量会更干净?

编辑:“工作”是指它应该在 0x100 处打印指向理论成员的指针。基本上,如果这相当于“std::cout

【问题讨论】:

  • 你如何定义“工作”?
  • 你所做的和arr + 0x100 都同样未定义。
  • 嗯。就像从数组的末尾读取 254 个条目一样?抱歉,但是阅读数组末尾的内容从来都不是干净的或好的做法。无论哪种方式也是UB。
  • @StoryTeller 我不认为它是等价的。从逻辑上讲是这样,但&amp;arr[0x100] 等同于*(arr+0x100),它取消了地址的引用,因此是未定义的行为。 arr + 0x100 只是一个地址计算。
  • @Jens - 这不是我的想法。这就是 C++ 标准对指针运算的规定。

标签: c++ arrays pointers


【解决方案1】:

使用我的编译器 (Cygwin GCC) 获取该值的地址与进行指针运算相同,尽管每个都是未定义的行为 (UB)。正如 Jens 在下面的评论中提到的,http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html,我发现以下内容很有帮助。

还值得指出的是,Clang 和 GCC 都明确了 C 标准未定义的一些行为。我将要描述的东西根据标准都是未定义的,并且在这两个编译器的默认模式下都被视为未定义的行为。

Wild Pointers 和越界数组访问的取消引用:取消引用随机指针(如 NULL、指向已释放内存的指针等)以及越界访问数组的特殊情况是 C 应用程序中的常见错误,希望无需解释。为了消除这种未定义行为的来源,必须对每个数组访问进行范围检查,并且必须更改 ABI 以确保范围信息遵循可能受到指针运算的任何指针。对于许多数值和其他应用程序而言,这将产生极高的成本,并且会破坏与每个现有 C 库的二进制兼容性。

指针运算也是UB。所以你有一个地址,但你不能取消引用指向它的指针。所以拥有这个地址真的没有任何用处。只是获取地址是UB,不应该在代码中使用。

有关越界指针,请参阅此答案: Why is out-of-bounds pointer arithmetic undefined behaviour?

我的示例代码:

    int* arr = new int[2];
    std::cout << arr << std::endl;
    std::cout << &(arr[0])<< std::endl;
    std::cout << &(arr[1])<< std::endl;
    std::cout << &arr[0x100] << std::endl; // UB, cannot be dereferenced
    std::cout << &arr[256] << std::endl;   // cannot be dereferenced, so no use in having it
    std::cout << arr + 0x100; // UB here too, no use in having this address 

样本输出:

0x60003ae50
0x60003ae50
0x60003ae54
0x60003b250
0x60003b250
0x60003b250

【讨论】:

  • “C++ 允许获取这些地址” - 不,它没有,标准说它是 UB
  • @Jens 感谢您的链接,我根据信息进行了更新。很有帮助。
  • @UnholySheep 真实,已取出。
  • 现在这个答案仍然听起来像代码没有调用 UB - 它确实,就像你的示例代码一样。指针算术也是UB
【解决方案2】:

在第一行中,您分配了 2 个整数值。在第二行中,您访问此范围之外的内存。这根本不允许。

编辑:这里有一些有趣的 cmets。但是我不明白,为什么要引用标准来获得这么简单的答案,为什么这里讨论了这么多指针运算?

从逻辑上看,std::cout

如果第一步无效,那么后面的不都是undefined吗?

【讨论】:

  • 站点标准或给出更多理由说明为什么这是 UB。这个答案只是一个评论。
  • 好吧,我从来没有真正访问过数据,因为它应该只给我指向 0x100 处的理论成员的指针。
  • @MichaelDorgan 我不认为“访问你不拥有的内存是 UB”这句话需要文档。但是我确实认为他需要解释内存实际上是“访问”的隐含假设(因为 OP 似乎不理解下标运算符在做什么)
  • 实际上,我认为 OP(原始 OP - 大声笑)确实如此 - 他也这么说。无论如何,我很确定在拥有的内存结束后超过 1 个条目的指针算术也被认为是 UB - 是否受到尊重。我今天早些时候在另一篇文章中看到了这一点。嗯……
  • 好吧,我从来没有真正访问过数据”,这听起来像是他没有意识到它实际上是在取消引用。但我不相信拥有内存之外的指针算术应该是UB ...如果你能找到那个帖子,我很高兴在这个问题上被证明是错误的! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-17
相关资源
最近更新 更多