【问题标题】:Why is undefined behavior allowed (as opposed to not compiling/crashing)?为什么允许未定义的行为(而不是不编译/崩溃)?
【发布时间】:2010-05-10 11:39:38
【问题描述】:

我了解编译器/解释器语言扩展的原因,但为什么没有有效定义的行为允许静默失败/做奇怪的事情而不是引发编译器错误?是因为编译器捕获它们的额外困难(不可能或只是耗时)?

附:哪些语言有未定义的行为,哪些没有?

P.P.S.是否存在并非不可能/在编译中需要很长时间才能捕获的未定义行为的实例,如果是,是否有任何充分的理由/借口。

【问题讨论】:

  • 一个相关的问题会涉及“实现定义的行为”,它没有“未定义的行为”那么糟糕,但仍然不理想。
  • 在某些语言中,函数参数的求值顺序,包括 + - * / 运算符,是未定义的。您真的希望用这种语言编写的程序无法编译吗?
  • @mouviciel:大概他希望语言在重要的地方定义评估顺序。

标签: language-agnostic compiler-construction compiler-errors unspecified


【解决方案1】:

在 C 和 C++ 等语言中需要未定义行为的概念,因为检测导致该行为的条件是不可能的或成本过高。以这段代码为例:

int * p = new int(0);
// lots of conditional code, somewhere in which we do
int * q = p;
// lots more conditional code, somewhere in which we do
delete p;
// even more conditional code, somewhere in which we do
delete q;

此处指针已被删除两次,导致未定义行为。对于像 C 或 C++ 这样的语言来说,检测错误太难了。

【讨论】:

  • 另请注意,允许未定义的行为在更现代的语言中变得不太常见。这使得实现编译器/运行时更加困难,但对于使用该语言的开发人员来说是一个巨大优势。
  • @Joachin 实际上,在我的代码中,我会说我可能每 6 个月遇到一次 UB 问题,如果那样的话。所以摆脱它对我来说并不是一个巨大的优势。
  • @Neil:我只是说 Java 等一些语言没有任何“未定义的行为”,这一事实使得推理代码变得非常 ,除其他外。
  • @Joachim:它使推理不正确的代码变得更容易(在 Java 中,您可以更加确信错误不是安全漏洞,即使它是安全漏洞,那也是部分是别人的错,而不仅仅是你的错)。一旦应用程序代码完成了它的设计目标,那么在其中任何一个中推理都同样容易。仅仅因为您可以在 Java 中使用空引用(抛出 NPE)或在 C 中取消引用空指针(未定义),并不意味着您在这两种语言中都处于有利位置,如果您的推理关于您的应用程序涉及这样做...
  • @JoachimSauer:这也与性能有关。只有当你携带额外的、不可见的标志、做一些簿记时,双重删除才会抛出,但这不是免费的。
【解决方案2】:

很大程度上是因为,为了实现某些目的,这是必要的。例如,C 和 C++ 最初用于编写操作系统,包括设备驱动程序之类的东西。为此,他们使用(除其他外)直接访问代表 I/O 设备的特定硬件位置。阻止对这些位置的访问会阻止 C 被用于其预期目的(而 C++ 专门针对允许所有与 C 相同的功能)。

另一个因素是在指定语言 和指定平台 之间的一个非常基本的决定。使用相同的示例,C 和 C++ 都基于有意识地决定将定义限制为语言,并将围绕该语言的平台分开。相当多的替代方案(以 Java 和 .NET 作为最明显的例子)指定整个平台。

这两者都反映了对设计态度的基本差异。 C 设计的基本准则之一(主要保留在 C++ 中)是“信任程序员”。尽管从未如此直接地陈述过,但 Java 的基本“沙盒”概念是/现在是基于您不应该信任程序员的想法。

至于哪些语言有/没有未定义的行为,这是一个肮脏的小秘密:出于所有实际目的,所有它们都有未定义的行为。一些语言(同样,C 和 C++ 是最好的例子)会付出相当大的努力来指出哪些行为是未定义的,而许多其他语言要么试图声称它不存在(例如 Java),要么大多忽略了许多“黑暗角落” " 它出现的地方(例如,Pascal,大多数 .NET)。

那些声称它不存在的人通常会产生最大的问题。例如,Java 包含许多尝试的规则来保证一致的浮点结果。在这个过程中,它们使得在相当多的硬件上有效地执行 Java 成为不可能——但浮点结果仍然不能真正保证是一致的。更糟糕的是,他们要求的浮点模型并不完全完美,因此在某些情况下,它阻止获得尽可能好的结果(或者至少让你做很多额外的工作来解决它的要求)。

值得称赞的是,Sun/Oracle 已经(终于)开始注意到这个问题,并且现在正在研究一个相当不同的浮点模型,这应该是一个改进。我不确定这是否已被合并到 Java 中,但我怀疑当/如果是的话,旧模型的代码和新模型的代码之间会有相当大的“裂痕”。

【讨论】:

    【解决方案3】:

    因为不同的操作系统运行方式不同(...),您不能只说“在这种情况下崩溃”,因为这可能是操作系统可以做得更好的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-27
      • 1970-01-01
      • 2020-02-15
      • 1970-01-01
      • 1970-01-01
      • 2011-03-05
      • 2012-10-09
      • 1970-01-01
      相关资源
      最近更新 更多