为啥没有返回语句时没有编译器错误?

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 .这是一本非常有启发性的读物。

【讨论】:

以上是关于为啥没有返回语句时没有编译器错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的代码在 else 语句后出现编译错误?

为啥使用 Visual Studio 而不是 GCC 编译时没有错误?

为啥当我有两个函数时编译器没有显示错误,一个将基类作为参数,一个将派生类作为参数?

为啥在 TypeScript 中的“任何”字段类型变量上使用“字符串”函数时没有编译时错误?

为啥编译时库模块中的包不存在,即使 Android Studio 显示代码中没有错误?

Visual Studio 2010在编译c++时为啥有错误也没有下划波浪线?