【问题标题】:Is omitting return statement undefined behaviour in C89 (aka ANSI C)?是否在 C89(又名 ANSI C)中省略了 return 语句未定义的行为?
【发布时间】:2015-03-28 00:24:48
【问题描述】:

考虑以下基本示例:

#include <stdio.h>

int main(void)
{
    printf("Hi there!\n");
}

它会调用 C89 中的未定义行为吗?我试图从this question 中获得一些意义,但大多数赞成的答案声称它是由实现定义的,而且这里绝对没有 UB(与 Keith Thompson 的 cmets,这看起来很矛盾)。

规范在 §3.16 定义和约定中说:

如果“应”或“不应”要求出现在 违反了约束。行为未定义。未定义的行为 在本国际标准中另有说明 “未定义的行为”或省略任何明确的定义 行为。这三者在侧重点上没有区别:它们 都描述了“未定义的行为”。

和§5.1.2.2.3 程序终止

main 函数的初始调用的返回等效于 使用main 函数返回的值调用exit 函数 作为它的论据。如果main 函数执行返回指定 无值,返回宿主环境的终止状态为 未定义。

我的理解是后一个子条款不包括缺少返回的情况,因为return 语句从未被调用过,因此前一个子条款适用。

但进一步阅读表明有所不同,§6.6.6.4 return 声明

如果执行了没有表达式的return 语句,并且值 函数调用被调用者使用,行为是未定义的。 到达终止函数的} 相当于执行一个 return 不带表达式的语句

好的,现在5.1.2.2.3 子条款适用:

如果main 函数执行返回指定 没有价值。返回宿主环境的终止状态为 未定义。

术语“终止状态未定义”似乎不是UB,也不是任何特定行为,而是更像是超出了C标准的范围,更像是:“让宿主环境不用担心,我们从这里洗手”。理解正确吗?

【问题讨论】:

  • 如果您还没有看到,这里有一些有趣的答案:stackoverflow.com/q/204476/3933332
  • My go-to C89 draft 与您给出的报价完全不符。章节号完全不同,对应的文字也不同。当然,这是一个草案,而不是最终标准。然而,如果我们不同意标准,我们就不可能就答案达成一致。
  • 我会读到这相当于在没有表达式的情况下调用return,然后根据§5.1.2.2.3 声明没有表达式的return 会导致未定义的返回码到主机操作系统.你是对的,这不是未定义的行为,因为发生的事情是已知的并且总是相同的;程序将终止,并将一个值作为返回码返回给操作系统。 is undefined 就是那个值。所以是的,我会说你的解释是正确的。
  • It is allowed in C99。虽然这不能回答您关于 C89 的问题,但我认为从编译器编写者的角度来看,在 C89 中触发 UB 但在 C99 中具有明确定义的行为会很疯狂。这甚至可能被认为是 C89 中的一个缺陷。
  • 根据您提供的标准摘录,我说在“返回到主机环境的终止状态未定义”中暗示到达main() 的尾随} 会导致程序终止。因此,这似乎已定义。我倾向于说它是未定义的,但是,在这种情况下是否调用exit(),如果是,那么它的参数的值肯定是未定义的。这些细节都在 C 标准的范围内,所以程序确实有未定义的行为。

标签: c language-lawyer c89


【解决方案1】:

几年前,我实际上调试了由此引起的问题。如果您有一些带有返回的代码路径而其他没有返回的代码路径,它会变得更加有趣。

正如@aruisdante 在 cmets 中推测的那样,表现出的行为确实是“未定义”,但唯一未定义的部分是返回的值(它不像许多其他可能导致程序崩溃的“未定义”情况)。

如今,这实际上构成了安全风险,因为返回的“未定义”值通常是 CPU 寄存器中通常用于返回值(或在某些实现中位于堆栈上)中的任何值,理论上可以用于泄露敏感数据。

【讨论】:

  • 你是指main函数,还是普通函数?
  • IIRC,它是main,但它回到了 90 年代初。那是很久以前的事了。
【解决方案2】:

我相信标准委员会的意图是未指定此终止状态值。

根据N739草稿:

并将第 5.1.2.2.3 条的最后一句从:

如果 /main/ 函数执行一个没有指定值的返回, 返回宿主环境的终止状态是undefined

到:

如果 /main/ 函数执行一个没有指定值的返回,|返回宿主环境的终止状态为 未指定

[未定义值的概念在其他地方被小心避免。]

您还可以在进一步的标准中发现,术语已更改,因此使用了术语“未指定”。

我会说它本身绝对不是未定义的行为,但仍然无法确定它是未指定的行为还是我所说的根本没有行为。其他摘录,表明后者是 §1 Scope

本国际标准未规定:

  • 调用 C 程序以供数据处理系统使用的机制;

我希望这也意味着该国际标准没有指定主机环境如何处理程序的终止状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多