【问题标题】:Can guaranteed UB be rejected at compile-time?可以保证 UB 在编译时被拒绝吗?
【发布时间】:2014-12-19 09:51:44
【问题描述】:

考虑这个程序:

#include <stdio.h>

int main(void)
{
    int x;
    while ( 1 == scanf("%d", &x) )
        printf("%c\n", "hello"[x]);
}

编译器必须编译成功,因为程序没有UB,只要用户没有输入任何超出0-4范围的数字。

但是,根据this thread UB 可以回到过去。现在考虑这个程序:

int main(void)
{ 
    printf("hello\n");
    "hello"[6];
}

对该程序的任何调用都会导致未定义的行为,并且由于它可以穿越时间,因此该程序在任何调用时的整个行为都是未定义的。因此编译器可以拒绝程序而不生成可执行文件吗? (我们可以说 UB 回到了编译阶段!)

【问题讨论】:

  • @Zaffy: "hello"[5]'\0'"hello"[6] 超出范围。
  • @Jarod42 哦,是的,对不起 :)
  • 可靠且可靠地检测未定义行为是一个难以处理或无法确定的问题......
  • 是的,完美的例子是constexpr,在这些情况下我们可以看到clanggccreject most undefined behavior at compile time
  • 请注意,在 UB 的情况下中止编译很常见:例如,Gcc 在void foo(void) { extern int n; } static int n; 上中止,尽管这是 UB 而不是违反约束。不过,IMO,你的例子有点不同。

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


【解决方案1】:

编译器能否因此拒绝程序而不生成可执行文件?

是的。未定义行为的定义是:

本国际标准没有要求的行为 [注意:当本国际标准省略任何明确的行为定义或程序使用错误的构造或错误数据时,可能会出现未定义的行为。允许的未定义行为 范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(有或没有发出诊断消息),终止翻译或执行(发出诊断消息)。 许多错误的程序结构不会产生未定义的行为;他们需要被诊断出来。 —结束注释]

【讨论】:

    【解决方案2】:

    添加到乔纳森的答案中。

    第二个程序调用未定义的行为,编译器有权停止翻译,因为未定义的行为不受限制(c11,3.4.3p1)。

    第一个程序可能会调用未定义的行为,但编译器无法停止翻译,因为并非所有执行路径都会产生未定义的行为。

    Defect Report #109,C 委员会说:

    此外,如果给定程序的每一次可能执行都会导致未定义的行为,那么给定程序就不是严格符合的。 符合标准的实现不能仅仅因为该程序的某些可能执行会导致未定义的行为而无法翻译严格符合标准的程序。

    【讨论】:

      猜你喜欢
      • 2014-12-19
      • 2014-11-13
      • 1970-01-01
      • 2012-03-22
      • 2016-10-28
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 2018-02-11
      相关资源
      最近更新 更多