为什么存在"未定义的行为"?

Qqw*_*qwy 9 c c++ compiler-errors compilation undefined-behavior

某些常见的编程语言,尤其是C和C++,具有未定义行为的强烈概念:当您尝试执行某些操作之外的某些操作时,这会导致未定义的行为.

如果发生未定义的行为,则允许编译器执行任何操作(包括任何内容,'时间旅行'等).

我的问题是:为什么存在这种未定义行为的概念?据我所知,如果不是导致未定义的行为,使用超出其预期用途的操作会导致大量的错误,使用一个版本的编译器停止工作的程序,等等将被阻止一个编译错误.

为什么这不是事情的方式?

eer*_*ika 12

为什么存在这种未定义行为的概念?

允许语言/库尽可能高效地在各种不同的计算机体系结构上实现( - 也许在C的情况下 - 同时允许实现保持简单).

如果不是导致未定义的行为,使用其预期用途之外的操作将导致编译错误

在大多数未定义行为的情况下,证明在编译时对于所有程序通常存在未定义的行为是不可能的 - 或者说资源过于昂贵.

有些案例可能会对某些程序进行证明,但不可能指定哪些案例是详尽的,因此标准不会尝试这样做.尽管如此,一些编译器足够聪明,可以识别UB的一些简单情况,这些编译器会向程序员发出警告.例:

int arr[10];
return arr[10];
Run Code Online (Sandbox Code Playgroud)

该程序具有未定义的行为.我测试的特定版本的GCC显示:

警告:数组下标10位于'int [10]'[-Warray-bounds]的数组范围之上

忽略这样的警告几乎不是一个好主意.


具有未定义行为的更典型的替代方案是在这种情况下定义错误处理,例如抛出异常(比较例如Java,其中访问空引用导致java.lang.NullPointerException抛出类型的异常).但是检查明确定义的行为的前提条件比不检查它要慢.

通过不检查前置条件,该语言为程序员提供了自己证明正确性的选项,从而避免了在被证明不需要它的程序中检查的运行时开销.实际上,这种力量带来了巨大的责任.

目前,使用添加了一些运行时检查的工具(示例)可以在一定程度上减轻证明程序定义良好的负担,并在检查失败时巧妙地终止程序.


Mic*_*zel 8

存在未定义的行为主要是为了使编译器可以自由地进行优化.例如,允许编译器执行的一件事是在假设某些事情不可能发生的情况下进行操作(无需首先证明它们不会发生,这通常是非常困难或不可能的).通过允许它假设某些事情不会发生,编译器可以消除/不必生成代替某些可能性所需的代码.

关于这个话题的好话