我们都听到了警告,如果您在C或C ++中调用未定义的行为,可能会发生任何事情。
这是否仅限于任何运行时行为,还是包含任何编译时行为?特别是,编译器在遇到调用未定义行为的构造时,允许拒绝代码(在标准中没有其他要求的情况下这样做),甚至崩溃?
答案 0 :(得分:16)
“你们都忽略了实际定义并专注于注释,标准强加无要求。” - @ R.MartinhoFernandes
上面的消息是由给定用户在 Lounge<C++> 中编写的,并且是一个非常有效的参数;当涉及调用未定义行为的代码时,标准不会强加任何要求。
undefined-behavior 甚至延伸到编译器解析输入数据(即代码)的远角,如下面的语句验证 C ++ 11 < / em>和 C99 标准。
用一句话回答你的问题;
“以文档化的方式表征环境”是一种奇怪的陈述,您几乎可以编写一个编译器,记录它可能会在任何给定的代码上崩溃(这是无效的,以便在任何时候允许它崩溃。
1。引用C ++ 11 / C99标准
1.3.24 [defns.undefined]
未定义的行为;这个国际标准的行为 没有要求
[注意:
可能会出现未定义的行为 当本标准省略任何明确的定义时 行为或程序使用错误的结构或错误 数据
允许的未定义行为范围从完全忽略不可预测的结果到在翻译期间表现 或者程序执行以有记录的方式表征 环境(有或没有发出诊断信息),到 终止翻译或执行(发布一份 诊断信息)。
许多错误的程序结构不会产生未定义的行为; 他们需要被诊断出来。
- 结束记录]
3.4.3 - 未定义的行为
使用不可移植或错误的程序构造或错误数据时,
- 醇>
注意可能未定义的行为范围从完全忽略情况,结果不可预测到在翻译过程中表现 或以程序化的方式执行 环境(有或没有发出诊断消息),到 终止翻译或执行(发布一份 诊断信息)。
答案 1 :(得分:10)
如果行为未定义,编译器可以接受它,拒绝它,发出警告,并根据标准,甚至在您的计算机上崩溃,挂起或安装病毒。
在实践中,这并不意味着如果你正在编写一个编译器,你应该故意做这些事情,但是你可以,例如,如果性能,你可以使用一个算法,该算法适用于定义的情况,崩溃或挂起未定义的情况优势证明了它。
尽管如此,一个声誉良好的编译器可以避免这种情况,或者至少有很好的记录。
答案 2 :(得分:2)
它不仅限于运行时行为。根据ISO / IEC 14882,第一版,1998-09-01,1.3.12,在一个注释(非规范性)中:“允许的未定义行为范围从...到以翻译或编程执行期间的行为表现形式特征环境“。换句话说,标准规定,实施可以执行操作系统(或其他环境)允许的任何操作,前提是它已被记录。
答案 3 :(得分:0)
我一直很喜欢标准报价,所以如果你正在寻找,那么标准将未定义的行为定义为
本国际标准没有要求的行为
[注意:当本国际标准忽略程序使用错误构造或错误数据时的行为的任何明确定义时,可能会出现未定义的行为。允许的未定义行为范围从完全忽略不完全结果的情况,到在翻译或程序执行期间行为以环境特征(有或没有发出诊断消息)的文档化方式来终止翻译或执行(发布诊断信息)。许多错误的程序结构不会产生未定义的行为;他们需要被诊断出来。 - 后注]
“翻译”基本上是从源头到最终产品(组装或其他)。所以我们可以混合这两种可能性并获得
在翻译过程中完全忽略了这种情况,结果不可预测
所以,是的,编译器可以在编译期间以及在运行时自由地展示未定义的行为。
答案 4 :(得分:0)
至少某些形式的未定义行为可能会导致编译行为本身在标准管辖范围之外的行为。例如,标准的作者不想排除使用
之类的东西#include `someProg arg`
或
#pragma exec-include "someProg arg"
作为使用给定参数运行someProg
的方法,并将此类程序的输出视为源文本的一部分。由于这种语法调用的程序的行为将超出标准的管辖范围,因此从标准的角度来看,这样的结构只是在编译时被视为调用UB。