【发布时间】:2015-07-01 01:19:39
【问题描述】:
因此,标准(参考N1570)对比较指针有以下说明:
C99 6.5.8/5 关系运算符
当比较两个指针时,结果取决于相对的 指向的对象的地址空间中的位置。 ... [剪断聚合内比较的明显定义] ... 在所有其他情况下, 行为未定义。
这个 UB 实例的基本原理是什么,而不是指定(例如)转换为 intptr_t 并进行比较?
是否有一些机器架构难以构建合理的指针总排序?是否存在某种类型的优化或分析会阻碍无限制的指针比较?
this question 的已删除答案提到,这段 UB 允许跳过段寄存器的比较,只比较偏移量。保存起来特别有价值吗?
(相同的已删除答案,以及此处的一个,请注意,在 C++ 中,std::less 等需要实现指针的总顺序,无论普通比较运算符是否执行。)
【问题讨论】:
-
委员会没有在其标准的官方理由中回答这个具体问题,所以任何答案都是推测性的,除非可能来自委员会成员。尽管如此,规范相关方面的官方理由考虑了聚合对象表示附近字节的分段架构和可寻址性,所以我倾向于猜测@cheersandhth 在他的回答中提到 C 的那部分是正确的。跨度>
-
分段架构让它变得很糟糕——正如在英特尔 80386 和相关产品上发现的那样。在过去 80286、80186、8086、8088 的糟糕日子里,这尤其痛苦。同一个地址可以有多个位表示。即使使用现代 Pentiums 和 x86_64s 等,理论上您也可以拥有分段地址;不过,没有人疯狂到可以使用它们。好吧,几乎没有人——我敢肯定还有人仍然在运行带有分段地址的软件。
-
这不是一个基于意见的问题,据我所知,C 和 C++ 标准中的所有未定义行为都有其合理性。它们是否易于从公共资源中辨别是另一个问题,但这并不会使它们成为坏问题。
-
@JonathanLeffler 这在微控制器中仍然很常见,因为在 70 年代、80 年代和 90 年代发明的旧 8/16 位微控制器架构仍在生产中使用。您将拥有“存储”内存和各种奇怪的指针类型来访问它。许多嵌入式程序员无缘无故地狂热地坚持这种陈旧的废话。
-
@Lundin:标准中没有任何内容要求整数表示的比较产生与指针比较相同的结果,即使在后者定义明确的情况下也是如此。嵌入式程序员通常需要能够调整现有设计。如果一个产品已经畅销十年并且人们继续购买它,但某个部件变得不可用,那么能够将现有代码用于新部件可能比从头开始重写所有内容更可取。对于需要与其他设备交互的产品(这可能取决于某些...
标签: c pointers language-lawyer undefined-behavior