如果函数没有返回值,并且返回类型有效,编译器是否可以抛出垃圾?

how*_*rks 14 c c++ initialization return-value garbage

如果函数的返回类型不是void,并且函数没有返回任何内容,那么我猜编译器会返回一个垃圾值(可能被视为未初始化的值).它发生在编译时,为什么不应该抛出错误呢?

例如,

int func1() {
    return; // error
}

int func2() {
    // does not return anything
}
Run Code Online (Sandbox Code Playgroud)

第二个func2应该抛出错误,但事实并非如此.有原因吗?我的想法是,它可以看作是一个未初始化的值,所以如果我们需要在第二种情况下抛出错误,那么我们需要抛出错误,如果一个值是未初始化的,比如说

  int i;  // error
  int i = 6;  // okay
Run Code Online (Sandbox Code Playgroud)

有什么想法,或者这是一个重复的问题?我感谢您的帮助.

Man*_*rse 17

在C++中,此类代码具有未定义的行为:

[stmt.return]/2 ...从函数末尾流出相当于没有值的返回值; 这会导致值返回函数中的未定义行为....

大多数编译器都会针对与问题类似的代码生成警告.

C++标准并不要求这是一个编译时错误,因为在一般情况下,很难正确地确定代码是否实际在函数末尾运行,或者函数是否通过异常退出(或者是一个longjmp)或类似的机制).

考虑

int func3() {
    func4();
}
Run Code Online (Sandbox Code Playgroud)

如果func4()抛出,那么这段代码完全没问题.编译器可能无法看到func4()(由于单独的编译)的定义,因此无法知道它是否会抛出.

此外,即使编译器可以证明func4()不抛出,它仍然必须证明func3()在它合法地拒绝该程序之前实际被调用.这种分析需要检查整个程序,这与单独的编译不兼容,并且在一般情况下甚至是不可能的.

  • 包括C#和Java在内的许多语言都需要在上面的例子中使用`return someValue;`语句,即使它永远不会被执行.语言设计是关于权衡,有用的诊断的相对价值与偶尔需要愚蠢的代码来安抚编译器.我不同意许多Java/C#决定,但这个特别的决定我并不赞同. (3认同)

Kei*_*son 10

在C中,引用N1256 6.9.1p12:

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

因此,非void函数无法返回值是合法的(但是一个坏主意),但如果它这样做并且调用者尝试使用结果,则行为是未定义的.注意,它不一定只返回一些任意值; 就标准而言,一切皆有可能.

前ANSI C没有void关键字,所以编写一个没有返回值的函数的方法是省略返回类型,使其隐式返回int.return在值返回函数中需要语句会破坏旧代码.它还需要编译器进行额外的分析,以确定所有代码路径符合return语句; 这样的分析对于现代编译器来说是合理的,但是当C首次标准化时,这可能是一个过度的负担.

C++稍微严格一些.在C++中:

流出函数末尾相当于没有值的返回 ; 这会导致值返回函数中的未定义行为.

因此,无论调用者是否尝试使用(不存在)结果,行为都是未定义的.

C和C++编译器当然可以警告缺少return语句,或关于在不执行return语句的情况下从函数末尾掉下来的控制路径,但各自的标准并不要求它们这样做.

  • 这种分析只在简单的情况下才合理 - 在复杂的情况下,编译器甚至可能没有足够的信息来知道它总是会遇到`return`语句. (2认同)

caf*_*caf 5

在 C 中,只要调用代码不尝试使用返回值,非 void 函数完成而不返回值实际上是合法的

另一方面,return没有表达式的语句不允许出现在非空函数中。

C99标准的相关部分是第一种情况的§6.9.1:

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

和 §6.8.6.4 对于第二种情况:

return没有表达式的语句只能出现在返回类型为 的函数中void