C++ 为什么在不返回值的情况下从非空函数的末尾流出不会产生编译器错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1610030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does flowing off the end of a non-void function without returning a value not produce a compiler error?
提问by Catskul
Ever since I realized many years ago, that this doesn't produce an error by default (in GCC at least), I've always wondered why?
自从我多年前意识到默认情况下这不会产生错误(至少在 GCC 中),我一直想知道为什么?
I understand that you can issue compiler flags to produce a warning, but shouldn't it always be an error? Why does it make sense for a non-void function not returning a value to be valid?
我知道你可以发出编译器标志来产生警告,但它不应该总是一个错误吗?为什么非 void 函数不返回有效值是有意义的?
An example as requested in the comments:
评论中要求的示例:
#include <stdio.h>
int stringSize()
{
}
int main()
{
char cstring[5];
printf( "the last char is: %c\n", cstring[stringSize()-1] );
return 0;
}
...compiles.
...编译。
采纳答案by fnieto - Fernando Nieto
C99 and C++ standards don't require functions to return a value. The missing return statement in a value-returning function will be defined (to return 0
) only in the main
function.
C99 和 C++ 标准不要求函数返回值。值返回函数中缺少的 return 语句将0
仅在main
函数中定义(以返回)。
The rationale includes that checking if every code path returns a value is quite difficult, and a return value could be set with embedded assembler or other tricky methods.
基本原理包括检查每个代码路径是否都返回一个值非常困难,并且可以使用嵌入式汇编程序或其他棘手的方法设置返回值。
From C++11draft:
来自C++11草案:
§ 6.6.3/2
§ 6.6.3/2
Flowing off the end of a function [...] results in undefined behavior in a value-returning function.
从函数的末尾流出 [...] 会导致返回值的函数中出现未定义的行为。
§ 3.6.1/5
§ 3.6.1/5
If control reaches the end of
main
without encountering areturn
statement, the effect is that of executingreturn 0;
如果控制到达结束而
main
没有遇到return
语句,则效果是执行return 0;
Note that the behaviour described in C++ 6.6.3/2 is not the same in C.
请注意,C++ 6.6.3/2 中描述的行为与 C 中的不同。
gcc will give you a warning if you call it with -Wreturn-type option.
如果你用 -Wreturn-type 选项调用它,gcc 会给你一个警告。
-Wreturn-typeWarn whenever a function is defined with a return-type that defaults to int. Also warn about any return statement with no return-value in a function whose return-type is not void (falling off the end of the function body is considered returning without a value), and about a return statement with an expression in a function whose return-type is void.
This warning is enabled by -Wall.
-Wreturn-type每当函数定义为默认为 int 的返回类型时发出警告。还警告在返回类型不是 void 的函数中任何没有返回值的 return 语句(从函数体的末尾脱落被认为没有返回值),以及关于在函数中具有表达式的 return 语句返回类型为空。
此警告由-Wall启用。
Just as a curiosity, look what this code does:
出于好奇,看看这段代码做了什么:
#include <iostream>
int foo() {
int a = 5;
int b = a + 1;
}
int main() { std::cout << foo() << std::endl; } // may print 6
This code has formally undefined behaviour, and in practice it's calling conventionand architecturedependent. On one particular system, with one particular compiler, the return value is the result of last expression evaluation, stored in the eax
register of that system's processor.
此代码具有正式未定义的行为,实际上它依赖于调用约定和体系结构。在一个特定的系统上,使用一个特定的编译器,返回值是最后一个表达式评估的结果,存储在该eax
系统处理器的寄存器中。
回答by John Kugelman
gcc does not by default check that all code paths return a value because in general this cannot be done. It assumes you know what you are doing. Consider a common example using enumerations:
默认情况下,gcc 不会检查所有代码路径是否都返回一个值,因为这通常无法完成。它假设您知道自己在做什么。考虑一个使用枚举的常见示例:
Color getColor(Suit suit) {
switch (suit) {
case HEARTS: case DIAMONDS: return RED;
case SPADES: case CLUBS: return BLACK;
}
// Error, no return?
}
You the programmer know that, barring a bug, this method always returns a color. gcc trusts that you know what you are doing so it doesn't force you to put a return at the bottom of the function.
程序员知道,除非出现错误,否则此方法始终返回颜色。gcc 相信你知道你在做什么,所以它不会强迫你在函数的底部放置一个 return 。
javac, on the other hand, tries to verify that all code paths return a value and throws an error if it cannot prove that they all do. This error is mandated by the Java language specification. Note that sometimes it is wrong and you have to put in an unnecessary return statement.
另一方面,javac 尝试验证所有代码路径是否都返回一个值,如果不能证明它们都返回一个值,则抛出错误。此错误是 Java 语言规范规定的。请注意,有时它是错误的,您必须放入不必要的 return 语句。
char getChoice() {
int ch = read();
if (ch == -1 || ch == 'q') {
System.exit(0);
}
else {
return (char) ch;
}
// Cannot reach here, but still an error.
}
It's a philosophical difference. C and C++ are more permissive and trusting languages than Java or C# and so some errors in the newer languages are warnings in C/C++ and some warnings are ignored or off by default.
这是哲学上的差异。C 和 C++ 是比 Java 或 C# 更宽容和更信任的语言,因此较新语言中的一些错误是 C/C++ 中的警告,并且默认情况下会忽略或关闭一些警告。
回答by AnT
You mean, why flowing off the end of a value-returning function (i.e. exiting without an explicit return
) is not an error?
你的意思是,为什么从返回值函数的末尾流出(即没有显式退出return
)不是错误?
Firstly, in C whether a function returns something meaningful or not is only critical when the executing code actually usesthe returned value. Maybe the language didn't want to force you to return anything when you know that you are not going to use it anyway most of the time.
首先,在 C 中,函数是否返回有意义的东西只有在执行代码实际使用返回值时才至关重要。当您知道大多数时候无论如何都不会使用它时,该语言可能不想强迫您返回任何内容。
Secondly, apparently the language specification did not want to force the compiler authors to detect and verify all possible control paths for the presence of an explicit return
(although in many cases this is not that difficult to do). Also, some control paths might lead into to non-returning functions- the trait that is generally non known to the compiler. Such paths can become a source of annoying false positives.
其次,显然语言规范不想强迫编译器作者检测和验证所有可能的控制路径是否存在显式return
(尽管在许多情况下这并不难做到)。此外,一些控制路径可能会导致不返回函数——编译器通常不知道的特征。这样的路径可能会成为令人讨厌的误报的来源。
Note also, that C and C++ differ in their definitions of the behavior in this case. In C++ just flowing off the end of a value returning function is always undefined behavior (regardless of whether the function's result is used by the calling code). In C this causes undefined behavior only if the calling code tries to use the returned value.
另请注意,在这种情况下,C 和 C++ 对行为的定义不同。在 C++ 中,从值返回函数的末尾流出总是未定义的行为(无论调用代码是否使用了函数的结果)。在 C 中,仅当调用代码尝试使用返回值时,这才会导致未定义的行为。
回答by Yakk - Adam Nevraumont
It is legal under C/C++ to not return from a function that claims to return something. There are a number of use cases, such as calling exit(-1)
, or a function that calls it or throws an exception.
在 C/C++ 下,不从声称返回某些内容的函数返回是合法的。有许多用例,例如调用exit(-1)
,或调用它或引发异常的函数。
The compiler is not going to reject legal C++ even if it leads to UB if you are asking it not to. In particular, you are asking for no warningsto be generated. (Gcc still turns on some by default, but when added those seem to align with new features not new warnings for old features)
编译器不会拒绝合法的 C++,即使它会导致 UB,如果您要求它不这样做。特别是,您要求不生成警告。(默认情况下,Gcc 仍然会打开一些,但是当添加时,这些似乎与新功能一致,而不是旧功能的新警告)
Changing the default no-arg gcc to emit some warnings could be a breaking change for existing scripts or make systems. Well designed ones either -Wall
and deal with warnings, or toggle individual warnings.
更改默认的 no-arg gcc 以发出一些警告可能是对现有脚本或 make 系统的重大更改。精心设计的要么-Wall
处理警告,要么切换个别警告。
Learning to use a C++ tool chain is a barrier to learning to be a C++ programmer, but C++ tool chains are typically written by and for experts.
学习使用 C++ 工具链是学习成为 C++ 程序员的障碍,但 C++ 工具链通常由专家编写并为专家编写。
回答by Yongwei Wu
In some limited and rare cases, flowing off the end of a non-void function without returning a value could be useful. Like the following MSVC-specific code:
在一些有限且罕见的情况下,从非空函数的末尾流出而不返回值可能很有用。像以下特定于 MSVC 的代码:
double pi()
{
__asm fldpi
}
This function returns pi using x86 assembly. Unlike assembly in GCC, I know of no way to use return
to do this without involving overhead in the result.
此函数使用 x86 程序集返回 pi。与 GCC 中的汇编不同,我知道没有办法在return
不涉及结果开销的情况下执行此操作。
As far as I know, mainstream C++ compilers should emit at least warnings for apparently invalid code. If I make the body of pi()
empty, GCC/Clang will report a warning, and MSVC will report an error.
据我所知,主流 C++ 编译器至少应该对明显无效的代码发出警告。如果我让body为pi()
空,GCC/Clang会报错,MSVC会报错。
People mentioned exceptions and exit
in some answers. Those are not valid reasons. Either throwing an exception, or calling exit
, will notmake the function execution flow off the end. And the compilers know it: writing a throw statement or calling exit
in the empty body of pi()
will stop any warnings or errors from a compiler.
人们exit
在一些答案中提到了例外情况。这些都不是正当理由。无论是抛出异常还是调用exit
,都不会使函数执行流程结束。编译器知道这一点:编写 throw 语句或调用exit
的空主体pi()
将停止来自编译器的任何警告或错误。
回答by d.lozinski
I believe this is because of legacy code (C never required return statement so did C++). There is probably huge code base relying on that "feature". But at least there is -Werror=return-type
flag on many compilers (including gcc and clang).
我相信这是因为遗留代码(C 从不需要 return 语句,C++ 也是如此)。可能有大量代码库依赖于该“功能”。但至少-Werror=return-type
在许多编译器(包括 gcc 和 clang)上都有标志。
回答by Chris Lutz
Sounds like you need to turn up your compiler warnings:
听起来您需要打开编译器警告:
$ gcc -Wall -Wextra -Werror -x c -
int main(void) { return; }
cc1: warnings being treated as errors
<stdin>: In function ‘main':
<stdin>:1: warning: ‘return' with no value, in function returning non-void
<stdin>:1: warning: control reaches end of non-void function
$
回答by David Thornley
Under what circumstances doesn't it produce an error? If it declares a return type and doesn't return something, it sounds like an error to me.
在什么情况下它不会产生错误?如果它声明了一个返回类型并且没有返回任何东西,对我来说这听起来像是一个错误。
The one exception I can think of is the main()
function, which doesn't need a return
statement at all (at least in C++; I don't have either of the C standards handy). If there is no return, it will act as if return 0;
is the last statement.
我能想到的一个例外是main()
函数,它根本不需要return
语句(至少在 C++ 中;我手边没有任何一个 C 标准)。如果没有返回,它将充当return 0;
最后一个语句。
回答by Matt B.
It is a constraint violation in c99, but not in c89. Contrast:
它在 c99 中是一个约束违规,但在 c89 中不是。对比:
c89:
c89:
3.6.6.4 The
return
statementConstraints
A
return
statement with an expression shall not appear in a function whose return type isvoid
.
3.6.6.4
return
声明约束
return
带有表达式的语句不应出现在返回类型为 的函数中void
。
c99:
c99:
6.8.6.4 The
return
statementConstraints
A
return
statement with an expression shall not appear in a function whose return type isvoid
. Areturn
statement without an expression shall only appear in a function whose return type isvoid
.
6.8.6.4
return
声明约束
return
带有表达式的语句不应出现在返回类型为 的函数中void
。return
没有表达式的语句只能出现在返回类型为 的函数中void
。
Even in --std=c99
mode, gcc will only throw a warning (although without needing to enable additional -W
flags, as is required by default or in c89/90).
即使在--std=c99
模式下,gcc 也只会抛出警告(尽管不需要启用额外的-W
标志,这是默认或 c89/90 所要求的)。
Edit to add that in c89, "reaching the }
that terminates a function is equivalent to
executing a return
statement without an expression" (3.6.6.4). However, in c99 the behavior is undefined (6.9.1).
编辑以在 c89 中添加,“到达}
终止函数的 等效于执行return
没有表达式的语句”(3.6.6.4)。但是,在 c99 中,行为未定义(6.9.1)。