“未定义的行为”是否延伸到编译时?

我们都听过警告,如果你在C或C ++中调用未定义的行为任何事情都可能发生。

这是否仅限于任何运行时行为 ,还是包含任何编译时行为? 特别是,编译器在遇到调用未定义行为的构造时,允许拒绝代码(在标准中没有其他要求的情况下这样做),甚至崩溃?

你们都忽略了实际的定义,并专注于注释,标准没有要求 ” – @ R.MartinhoFernandes

上面的消息是由给定的用户在Lounge 中编写的,并且是一个非常有效的参数; 当涉及调用未定义行为的代码时,标准不会强加任何要求


! ! !

undefined-behavior甚至延伸到编译器解析输入数据(即代码)的远角,如下面C ++ 11C99标准的引用所证实的那样。

用一句话回答你的问题 ;

  • 未定义的行为不仅限于运行时执行,并且允许在编译期间“以文档化的方式表征环境” 1崩溃 1

“以文档化的方式表征环境”是一种奇怪的陈述,你几乎可以编写一个编译器来记录它可能会崩溃任何给定的代码(这是无效的),以便它可以随时崩溃。

1.引用C ++ 11 / C99标准


C ++ 11

1.3.24 [defns.undefined]

未定义的行为 ; 本国际标准没有要求的行为

[ 注意

当本国际标准忽略任何明确的行为定义或程序使用错误的构造或错误数据时,可能会出现未定义的行为。

允许的未定义行为包括完全忽略不可预测的结果在翻译程序执行过程中以环境特征(有或没有发出诊断消息)的特定行为, 终止翻译或执行 (发布时)一条诊断信息)。

许多错误的程序结构不会产生未定义的行为; 他们需要被诊断出来。

结束说明 ]


C99

3.4.3 – 未定义的行为

  1. 在使用不可移植或错误的程序结构或错误数据时,此行为>国际标准不要求

  2. 注意可能的未定义行为范围从完全忽略不完全结果的情况 ,到翻译或程序执行期间的行为 ,以文档特有的环境( 有或没有发出诊断消息 ), 终止翻译或执行 (使用发出诊断信息)。

如果行为未定义,编译器可以接受它,拒绝它,发出警告,并根据标准,甚至崩溃,挂起或在您的计算机上安装病毒。

在实践中,这并不意味着如果你正在编写一个编译器,你应该故意做这些事情,但是你可以,例如,如果性能优势certificate它可以使用一个算法,该算法适用于定义的情况,崩溃或挂起未定义的情况。 。

仍然,一个声誉良好的编译器会避免这种情况,或者至少有一个很好的记录。

它不仅限于运行时行为。 根据ISO / IEC 14882,第一版,1998-09-01,1.3.12,在一个注释(非规范性)中:“允许的未定义行为范围从…到以翻译或编程执行期间的行为表现forms特征环境“。 换句话说,标准规定,实施可以执行操作系统(或其他环境)允许的任何操作,前提是记录在案。

我总是喜欢标准引号,所以如果你正在寻找,那么标准将未定义的行为定义为

本国际标准没有要求的行为

[注意:当本国际标准忽略程序使用错误构造或错误数据时的行为的任何明确定义时,可能会出现未定义的行为。 允许的未定义行为包括完全忽略不可预测的结果, 在翻译或程序执行过程中以环境特征(有或没有发出诊断消息)的特定行为,终止翻译或执行(发布时)一条诊断信息)。 许多错误的程序结构不会产生未定义的行为; 他们需要被诊断出来。 – 尾注]

而“翻译”基本上是从源头到最终产品(组装或其他)。 所以我们可以将这两种可能性混合起来

在翻译过程中完全忽略了这种情况,结果不可预测

所以是的,编译器可以在编译期间以及在运行时自由地展示未定义的行为。

至少某些forms的未定义行为可能导致编译行为本身在标准管辖范围之外的行为。 例如,标准的作者不想排除使用类似的东西

#include `someProg arg` 

要么

 #pragma exec-include "someProg arg" 

作为使用给定参数运行someProg一种方法, someProg此类程序的输出视为源文本的一部分。 由于这种语法调用的程序的行为将超出标准的管辖范围,因此从标准的角度来看,这样的结构只是在编译时被视为调用UB。