Grz*_*ski 15 c c89 language-lawyer
考虑以下基本示例:
#include <stdio.h>
int main(void)
{
printf("Hi there!\n");
}
Run Code Online (Sandbox Code Playgroud)
它是否在C89中调用未定义的行为?我试图从这个问题中得到一些意义,但是大多数赞成的答案声称它是实现定义的,绝对没有UB(与Keith Thompson的评论,看起来相互矛盾).
规范在§3.16 定义和惯例中说明:
如果违反约束之外出现的"应"或"不应"要求.行为未定义.未定义的行为在本国际标准中以"未定义的行为" 或省略任何明确的行为定义来表示.这三者之间的重点没有区别:它们都描述了"未定义的行为".
和§5.1.2.2.3 程序终止:
从初始调用到
main
函数的返回等效于使用exit
函数返回的值main
作为其参数调用函数.如果main
函数执行不指定值的返回,则返回到主机环境的终止状态是未定义的.
我的理解是,后面的子条款不包括丢失返回的情况,因为return
声明从未被调用过,因此以前的子条款适用.
然而futher读数表明不同的东西,§6.6.6.4 的return
声明:
如果执行了
return
没有表达式的语句,并且调用者使用了函数调用的值,则行为是未定义的. 到达}
那个终止函数等同于执行return
没有表达式的 语句.
好的,所以现在的5.1.2.2.3
子条款适用:
如果
main
函数执行不指定值的返回.返回到主机环境的终止状态是未定义的.
术语"终止状态未定义"似乎不是UB,也不是任何特定行为,但更像是在C标准范围之外,更像是:"让主机环境变得烦恼,我们洗手这里".这是正确的解释吗?
几年前,我实际上调试了由此引起的问题。如果您有一些带有返回值而另一些则没有返回值的代码路径,它会变得更加有趣。
正如 @aruisdante 在评论中推测的那样,所表现出的行为确实是“未定义”的,但唯一未定义的部分是返回的值(它不像许多其他可能导致程序崩溃的“未定义”情况)。
如今,这实际上构成了安全风险,因为返回的“未定义”值通常是通常用于返回值的 CPU 寄存器中(或在某些实现中的堆栈上)中发生的任何值,理论上这可用于泄漏敏感数据。