当 return 语句不存在时,为什么没有任何编译器错误?
与 Java 不同,在 C/C++ 中允许:
int* foo ()
{
if(x)
return p;
// What if control reaches here?
}
这通常会导致崩溃并且很难调试问题。为什么标准不强制要求非void
函数有最终返回? (编译器会因错误的返回
值而生成错误。)
GCC 或 MSVC 强制执行此操作? (类似-Wunused-result
)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这是不允许的(未定义的行为)。然而,该标准不要求在这种情况下进行诊断。
标准不要求最后一个语句
return
,因为这样的代码:它总是返回 0,但愚蠢的编译器看不到它。请注意,该标准并不强制要求智能编译器。
while
块之后的return
语句将是一种浪费,愚蠢的编译器无法对其进行优化。该标准不想要求程序员仅仅为了满足愚蠢的编译器而编写垃圾代码。g++ -Wall 足够聪明,可以在我的机器上发出诊断信息。
It is not allowed (undefined behaviour). However, the standard does not require a diagnostic in this case.
The standard doesn't require the last statement to be
return
because of code like this:This always returns 0, but a dumb compiler cannot see it. Note that the standard does not mandate smart compilers. A
return
statement after thewhile
block would be a waste which a dumb compiler would not be able to optimise out. The standard does not want to require the programmer to write waste code just to satisfy a dumb compiler.g++ -Wall is smart enough to emit a diagnostic on my machine.
在 -Wall 标志“https://en.wikipedia.org/wiki/GNU_Compiler_Collection”rel="nofollow noreferrer">GCC。
或更具体地说, -Wreturn 类型。
Use the -Wall flag in GCC.
Or more specifically, -Wreturn-type.
我的猜测:因为有时程序员比编译器更了解。通过这个简单的示例,很明显有些地方是错误的,但请考虑许多值的切换,或者一般情况下的许多检查。作为编码员,您知道某些值不会传递给函数,但编译器不会,只是提示您可能存在问题。
请注意,MSVC 上的甚至警告级别 1 也会发出以下警告:
My guess: Because sometimes the programmer knows better than the compiler. With this simple example, it's clear that someting is wrong, but consider a switch of many values, or many checks in general. You, as the coder, know that certain values just will not be passed in to the function, but the compiler doesn't and just hints you, that there might be something wrong.
Note that even warning level 1 on MSVC gives the following warning:
您可以使用以下编译器选项
-Wreturn-type -Werror=return-type
将警告转换为错误。
查看此链接
You can convert the warning into an error by using the following compiler options
-Wreturn-type -Werror=return-type
.Check out This link
显而易见的答案是:因为这不是错误。这只是一个错误,如果
x
为 false,如果调用者使用返回值,则两者都不是必须由编译器确定,至少在一般情况下
案件。
在这种特殊情况下(返回指针),它不会太
很难要求所有路径都返回; Java就是这样做的。在
然而,一般来说,在 C++ 中要求这样做是不合理的,因为在
C++,您可以返回用户定义的类型,而这可能是不可能的
构造一个值(没有默认构造函数等)所以我们有
程序员可能无法提供
返回
的情况在他或她知道不能被采用的分支中,并且编译器不能
确定该分支不能被采用。
在这种情况下,当它可以确定流程时,大多数编译器都会发出警告。
我见过的所有这些在某些情况下也明确发出警告
然而,不可能从末端掉下来。 (g++ 和 VC++ 都会警告:
,至少在通常的选项中是这样。尽管很明显,这
函数永远不会掉到最后。)
The obvious answer is: because it's not an error. It's only an error if
x
is false and if the caller uses the return value, neither of whichcan necessarily be determined by the compiler, at least in the general
case.
In this particular case (returning a pointer), it wouldn't be too
difficult to require a
return
for all paths; Java does this. Ingeneral, however, it's not reasonable in C++ to require this, since in
C++, you can return user defined types for which it may be impossible to
construct a value (no default constructor, etc.) So we have the
situation where the programmer might not be able to provide a
return
in a branch that he or she knows can't be taken, and the compiler can't
determine that the branch can't be taken.
Most compilers will warn in such cases, when it can determine the flow.
All of the ones I've seen also warn in some cases where it's clearly
impossible to fall off the end, however. (Both g++ and VC++ warn about:
, at least with the usual options. Although it's quite clear that this
function never falls off the end.)
据我所知,Visual Studio 2008 会警告您“执行路径没有返回值”。这是允许的,意思是“C++ 不会阻止你搬起石头砸自己的脚”。所以你要思考,而不是编译器。
As far as I remember, Visual Studio 2008 warns you about a "execution path that does not have a return value". It is allowed in the meaning of that "C++ won't stop you from shooting you in the foot". So you are to think, not the compiler.
标准对这种编程的说法是它会产生未定义的行为。
未定义的行为是 C/C++ 的快乐和遗憾,但它也是语言设计的一个基本特征,它允许许多低级优化,使 C 成为一种“高级汇编程序”(实际上它不是) ,但只是为了给你一个想法)。
因此,在重定向到 John 关于与 GCC 一起使用的切换的回答时,要了解“为什么”该标准不会阻止这种情况,我会指出对未定义行为及其所有奥秘的非常有趣的分析: 每个 C 程序员都应该了解关于未定义行为的知识。这是一本非常有启发性的读物。
What the standard says about this kind of programming is that it produces undefined behavior.
Undefined behavior is the joy and pity of C/C++, but it is also a fundamental feature of the language design that allows for many of the low-level optimizations that make C a sort of "high level assembler" (it is not, actually, but just to give you an idea).
So, while redirecting to John's answer about the switch to use with GCC, to know "why" the standard does not prevent that, I would point to a very interesting analysis of undefined behavior and all of its misteries: What Every C Programmer Should Know About Undefined Behavior. It makes for a very instructive reading.