为什么"并非所有控制路径都返回值"是警告而不是错误?

Nav*_*een 28 c++ compiler-warnings

我试图回答这个问题.正如接受的答案所暗示的那样,该代码的问题在于并非所有控制路径都返回一个值.我在VC9编译器上尝试了这个代码,它给了我一个相同的警告.我的问题是为什么只是一个警告而不是错误?此外,如果没有返回值的路径被执行,该函数将返回什么(它必须返回一些东西)?它只是堆栈顶部的任何东西还是可怕的未定义行为?

CB *_*ley 30

无法从具有非void返回类型的函数返回值会导致未定义的行为,但不是语义错误.

据我所知,其原因主要是历史性的.

C最初没有void和隐含int意味着大多数函数返回一个,int除非显式声明返回别的东西,即使没有意图使用返回值.

这意味着很多函数返回一个int但没有显式设置返回值,但这是好的,因为调用者永远不会使用这些函数的返回值.

有些函数确实返回了一个值,但使用了隐式,int因为它int是一个合适的返回类型.

这意味着预void编码具有许多名义上返回的功能,int但可以声明返回void,许多其他功能应该返回int,没有明确的方法来区分.在任何阶段强制执行return所有非void函数的所有代码路径都会破坏遗留代码.

还有一个论点是函数中的某些代码路径可能无法访问,但这可能不容易从简单的静态分析中确定,那么为什么强制执行不必要的return

  • 如果你想到`switch`就可以很容易地解释静态分析,而强烈建议你提供一个`default`,它不是必需的,也可能没有必要......但是编译器应该如何知道呢?另一方面......你应该在编译时将警告视为错误,这样会更好. (2认同)

tyr*_*nid 9

我猜它只是一个警告,因为编译器不能总是100%确定它可能不会返回.

即如果你有:


-= source1.c =-
int func()
{
    if(doSomething())
    {
       return 0;
    }
}

-= source2.c =-
int doSomething()
{
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,编译器可能无法知道它总是会返回返回,但是你会这样做.当然,依赖于了解外部代码的工作方式,这是一种糟糕的编程习惯.

至于实际返回的内容取决于平台.在x86 ABI上,EAX用于返回值(最多32位),因此它将返回放置在该寄存器中的内容(可能是来自其他内容的返回,临时值或总垃圾).


Cas*_*Cow 6

从技术上讲,如果调用一个函数并且该函数总是抛出异常,则不能保证会出错.例如,这里有一些伪代码,你知道raiseError总是抛出.

MyClass func( params )
{
     if( allIsValid() )
     {
       return myObject;
     }
     else
     {
        raiseError( errorInfo );
     }
}
Run Code Online (Sandbox Code Playgroud)

如果编译器看不到raiseError的实现,它就不会知道该函数是否会抛出.所以实际上这里确实没有未定义的行为.当然,在这里使编译器静音是很好的,你可以在raiseError之后写一个"虚拟"返回语句,或者使用虚拟"throw".我把它们称为"虚拟",因为它们永远不会实现.(如果你真的坚持,你也可以取消警告).但是没有错误或未定义的行为.