【问题标题】:Why some things left undefined behavior in C++? Wouldn't it be better if some of them pre-defined in the standard?为什么有些东西在 C++ 中留下了未定义的行为?如果其中一些在标准中预先定义,会不会更好?
【发布时间】:2015-03-12 05:15:51
【问题描述】:

我是 C++ 程序员。在冲浪期间,我熟悉了诸如未定义行为、未指定行为、实现定义行为等术语。我想知道为什么有些事情没有定义?我知道 C++ 与硬件很接近,但是为其中一些定义行为真的很难吗?如果是这样,他们为什么不这样做?这个问题是关于为编译器实现留下这么多行为的背后的哲学。我认为并相信这样做有以下两个优点:

1) 它可以提供更好的性能。它简化了编译器的工作,使得在某些情况下生成非常高效的代码成为可能。

2) 它允许编译器供应商灵活地以自己的方式实现它 大大地。

如果您知道性能以外的任何其他因素,请告诉我。 我们将非常感谢您的帮助。

谢谢

【问题讨论】:

  • “C++ 标准应该更长”从来没有人说过。也就是说,虽然这肯定是一个有趣的问题,但我不确定它是否属于 SO。
  • 一个例子:在类型宽度上左移是未定义的行为,因为某些 CPU 不会屏蔽移位量
  • 这并不能回答问题,但那些文章让我在 UB 上读了一遍:blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
  • @meet 我是这么认为的,所以我说它不会回答你的问题。但是对于其他读者来说,这可能非常有用。

标签: c++ language-lawyer undefined-behavior


【解决方案1】:

除了您已经提到的原因之外,重要的一件事是了解 CPU 的不同。他们仍然这样做,但以前更糟。试图准确指定 C++ 在极端情况下的行为方式是没有帮助的。例如。 0/0 会被不同的 CPU 以不同的方式处理,这对于真正的程序来说并不重要。

另一个问题是某些 UB 很难检测到。例如,跨翻译单元违反单一定义规则将需要在链接器阶段提供支持,并且对于依赖原始链接器的供应商有相当多的容忍度。

【讨论】:

  • 从历史上看,“未定义行为”的意思是“做平台上自然会发生的事情”。如果除以零触发了一个没有人愿意设置向量的硬件陷阱,那么任何事情都可能发生,但是在大多数具有硬件陷阱的实现中,人们可以假设除以零会触发陷阱或没有其他后果(例如,编译器实现未使用除法的结果可能会完全省略它)。然而,今天,“未定义的行为”不再受时间和因果律的约束。
【解决方案2】:

C++ 的设计理念不会强迫您做出选择。如果某些东西受到架构的限制,那么就会有限制,否则很少有关于语义的任意决定,可以有多种解释。

如果您查看一些未定义行为的案例 - 空指针引用、浮点溢出等。计算机和操作系统的实际行为或多或少是不确定的。当内存错误发生时,您不能假设硬件是否会陷入陷阱,或者操作系统特定的运行时是否能够以有效的方式运行。

我们碰巧主要使用基于 x86 的机器,以及在合理程度上遵循 POSIX 的保护模式操作系统。但这并不总是正确的。

存在一些架构,其中仅初始化指向无效地址的指针会导致硬件陷阱 - 您甚至不必取消引用它。

存在未定义行为的大多数情况是因为它是 未定义 像 1/0

【讨论】:

  • 最初,许多事情被保留为未定义行为,以允许各种实现可能具有程序员可能认为有用的不同“自然”行为。不幸的是,现代编译器哲学似乎朝着一个非常不同的方向发展,导致未定义行为的代码可能由编译器以与硬件“自然”所做的任何事情完全无关的奇怪方式编写(包括让编译器绕过检查会允许代码处理行为的“自然”后果)。
猜你喜欢
  • 2015-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-06
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
相关资源
最近更新 更多