为啥没有返回语句时没有编译器错误?
Posted
技术标签:
【中文标题】为啥没有返回语句时没有编译器错误?【英文标题】:Why there is no compiler error when return statement is not present?为什么没有返回语句时没有编译器错误? 【发布时间】:2011-06-07 05:24:02 【问题描述】:与 Java 不同,在 C/C++ 中,允许:
int* foo ()
if(x)
return p;
// what if control reaches here
这通常会导致崩溃和难以调试的问题。为什么标准不强制对非void
函数进行最终返回? (编译器会为错误的return
值生成错误)
gcc/msvc 中是否有任何标志来强制执行此操作? (类似于-Wunused-result
)
【问题讨论】:
下面的要点是:如果您想要这些类型的检查,请在 gcc 上使用-Wall
,并在 Visual Studio 中使用高警告级别(3 或 4)。
我一直希望有一个编译器标志,它会导致所有函数的末尾都有throw "LOL Y U HERE??";
。行为是未定义的,所以任何事情都可能发生,并且抛出异常当然可以作为任何事情。仅用于测试目的;我会同意他们在发布时得到优化。
如果x
被声明为const bool x = true;
,则不是未定义的。
@Dennis:IIRC,在函数末尾运行不是 UB,除非调用者尝试使用返回值。
风格差和UB是有区别的。
【参考方案1】:
这是不允许的(未定义的行为)。但是,在这种情况下,该标准不需要诊断。
标准不要求最后一条语句为return
,因为代码如下:
while (true)
if (condition) return 0;
这总是返回 0,但愚蠢的编译器看不到它。请注意,该标准不强制要求智能编译器。 while
块之后的 return
语句将是一种浪费,愚蠢的编译器将无法优化。该标准不想要求程序员编写废代码只是为了满足愚蠢的编译器。
g++ -Wall 足够聪明,可以在我的机器上发出诊断信息。
【讨论】:
“请注意,该标准不强制要求智能编译器。” +1。 我认为更好的例子是:int test(...) if (...) [compute something and return it]; else log_something(...); FATAL_ERROR(); ;
。如果FATAL_ERROR()
无法返回,则永远无法到达test()
的末尾,但编译器通常无法知道这一点。
如果条件为假(无前进),此代码会导致未定义的行为
@M.M 这不是文字代码。 condition
代表任何表达式。【参考方案2】:
在gcc
中使用-Wall
标志。
warning: control reaches end of non-void function
EDIT:或者更具体地说是-Wreturn-type
。
【讨论】:
IIRC gcc 仅在打开优化时对其进行诊断,因为它使用控制流分析来诊断它并且在不优化时不会运行。 @T.j.克劳德:For C ++ , a function without return type always produces a diagnostic message, even when -Wno-return-type is specified. The only exceptions are main and functions defined in system headers
- 来自gcc man
页面
有趣,如果我在 main
中检测到它,gcc 并没有用 -Wall
检测到它,分支到 argc
。但是如果我添加了一个单独的函数并在其中执行它,它确实 检测到它。 main
似乎是一个特例(因为它在很多方面都是如此)。 编辑:@John:重叠 cmets。 :-)
@T.J main()
不需要包含明确的return
值;见 Bjarne Stroustrup 网站www2.research.att.com/~bs/bs_faq2.html#void-main
它是由标准定义的,在here查看Shafik的答案【参考方案3】:
我的猜测:因为有时程序员比编译器更了解。通过这个简单的示例,很明显有些地方是错误的,但考虑一个切换多个值或多个检查的一般情况。作为编码人员,您知道某些值不会传递给函数,但编译器不会,只是提示您,可能有问题。
#include <iostream>
int foo()
if(false)
return 5;
int main()
int i = foo();
std::cout << i;
请注意,MSVC 上的 even warning level 1 会发出以下警告:
警告 C4715: 'foo' : 并非所有控制路径都返回值
【讨论】:
"请注意,即使 MSVC 上的警告级别 1 也会发出以下警告:" 这很有趣。即使是 VS 2005 的第 4 级,我也没有得到。 @T.J.:根据 MSDN,2005 也应该在 1 级发出警告。请参阅我添加的链接。 @Xeo:令人着迷。如果我添加像您这样的foo
函数,我会收到错误,但如果我在自动生成的_tmain
函数中执行完全相同的操作,则不会; example。主要功能是特殊的(就像很多事情一样)。
这样的控制流警告通常仅在优化器运行并进行分析时才会发出。因此,它们通常仅限零售。
@example:这是因为标准明确允许main
没有返回语句。如果省略,结果就好像最后是return 0;
。【参考方案4】:
您可以使用以下编译器选项将警告转换为错误
-Wreturn-type -Werror=return-type
。
看看这个link
【讨论】:
【参考方案5】:AFAIR Visual Studio 2008 警告您“没有返回值的执行路径”。意思是“C++ 不会阻止你踢你的脚”是允许的。所以你要思考,而不是编译器。
【讨论】:
【参考方案6】:显而易见的答案是:因为这不是错误。这只是一个错误,如果
x
为假,如果调用者使用返回值,两者都不是
必须由编译器确定,至少在一般情况下
案例。
在这种特殊情况下(返回一个指针),它不会太
很难为所有路径要求return
; Java 就是这样做的。在
然而,一般来说,在 C++ 中要求这个是不合理的,因为在
C++,您可以返回可能无法返回的用户定义类型
构造一个值(没有默认构造函数等)所以我们有
程序员可能无法提供return
的情况
在他或她知道不能被采用的分支中,编译器不能
确定不能取分支。
大多数编译器会在这种情况下发出警告,当它可以确定流程时。 在某些情况下,我所见过的所有情况都会发出警告 然而,不可能从头上掉下来。 (g++ 和 VC++ 都警告:
int
bar( char ch )
switch ( ch & 0xC0 )
case 0x00:
case 0x40:
return 0;
case 0x80:
return -1;
case 0xC0:
return 1;
,至少使用通常的选项。虽然很清楚这 功能永远不会落到最后。)
【讨论】:
【参考方案7】:标准对这种编程的描述是它会产生未定义的行为。
未定义的行为是 C/C++ 的乐趣和遗憾,但它也是语言设计的一个基本特征,允许许多低级优化使 C 成为一种“高级汇编程序”(它是不是,实际上,只是给你一个想法)。
因此,在重定向到约翰关于使用 GCC 的开关的回答时,要知道“为什么”标准不会阻止这一点,我会指出对未定义行为及其所有谜团的非常有趣的分析:What Every C Programmer Should Know About Undefined Behavior .这是一本非常有启发性的读物。
【讨论】:
以上是关于为啥没有返回语句时没有编译器错误?的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用 Visual Studio 而不是 GCC 编译时没有错误?
为啥当我有两个函数时编译器没有显示错误,一个将基类作为参数,一个将派生类作为参数?
为啥在 TypeScript 中的“任何”字段类型变量上使用“字符串”函数时没有编译时错误?