繁体   English   中英

为什么标准允许不返回编译的函数?

[英]Why does the standard let functions that don't return compile?

即使它的签名说它应该,f()也不会返回。 为什么允许这个编译? C标准是否有理由不要求编译器使其失败?

我知道它是未定义的行为和所有,但为什么它首先被允许? 有历史原因吗?

double f(){}

int main()
{
    f();
    return 0;
}

C标准是否有理由不要求编译器使其失败?

通过调用未定义的行为,C标准允许编译器不那么复杂。 确实存在一些情况,例如if语句,很难说函数是否返回值:

int f(int n)
{
  if (n > 0) return 1;
}
  • 如果我写f(5) ,编译器很容易说该函数是正确的。
  • 如果我写f(-5) ,也很容易检测到未定义的返回值。

但是,如果参数来自用户输入,例如,编译器应该如何知道函数是否返回值? 由于这可能是一个有效或错误的程序,C标准允许编译器做他们想要的。 C旨在尽可能智能和简单。

编译器肯定分析函数的所有代码路径,并拒绝该计划,如果它不能证明该函数总是返回一个有意义的值。 我认为标准没有强制要求的原因是,在过去,编译器的复杂性远远低于我们今天的工作。

当然使用这种函数的返回值是未定义的行为:

如果到达终止函数的},并且调用者使用函数调用的值,则行为是未定义的。

很容易判断您的函数将在不返回值的情况下到达终点。 它不会返回也不会调用任何可能阻止它到达终点的代码(如abort() )。

事实上,您的程序在C99中没有未定义的行为,因为调用者不会使用缺少的返回值。 6.9.1 / 12:

如果到达终止函数的},并且调用者使用函数调用的值,则行为未定义。

所以你的代码风格有问题,但定义明确。

C ++标准更改了[diff.stat]该更改的规则和备注。 它说规则的C版本是支持在C不区分int return和void return的日子里写回的代码。 因此,您的代码首先定义行为的原因是“遗留”。 也就是说,AFAIK C总是区分double返回和int返回,因此如果在正确的时间完成,它可能会使UB成为一个返回double尾的函数。

暂且不管是否使用了返回值,请考虑一个tricker函数:

double f() {
    if (g()) exit();
}

此函数也不包含return语句,但如果实际上g总是返回true值或根本不返回,则不会到达函数的末尾。 因此,即使使用其返回值,也应该接受此函数,在一般的C标准原则上,您应该知道您正在做什么并且意味着您所说的。 如果g在不同的TU中定义,那么您可能比编译器更了解它。

即使它不是出于遗留原因,我也很确定标准根本无法添加文本以便定义需要检测的非返回场景编译器。 这取决于实现的质量 - 如果可以在编译时确定您的函数不可能避免UB,那么编译器可能会发出警告,尽管不需要诊断。 就此而言,当一般的C 实施者的原则定义行为时,它偶尔会发出警告,即某些事情是如此愚蠢,以至于任何用户都无法合理地表达它们。

因为编译器无法判断函数是否在运行时返回。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM