我试图回答this问题。正如接受的答案所暗示的那样,该代码的问题在于并非所有控制路径都返回一个值。我在VC9编译器上尝试了这个代码,它给了我一个相同的警告。我的问题是为什么只是一个警告而不是错误?此外,如果没有返回值的路径被执行,该函数将返回什么(它必须返回一些东西)?它只是堆栈顶部的任何东西还是可怕的未定义行为?
答案 0 :(得分:30)
无法从具有非void
返回类型的函数返回值会导致未定义的行为,但不是语义错误。
据我所知,其原因主要是历史性的。
C最初没有void
而隐式int
意味着大多数函数返回int
,除非显式声明返回其他内容,即使无意使用返回值
这意味着很多函数返回一个int但没有显式设置返回值,但这是好的,因为调用者永远不会使用这些函数的返回值。
某些函数确实返回了一个值,但使用了隐式int
,因为int
是一个合适的返回类型。
这意味着前void
代码有许多名义上返回int
但可以声明返回void
的函数以及许多应该返回{{1}的其他函数没有明确的方法来区分。在任何阶段对所有非int
函数的所有代码路径执行return
都会破坏遗留代码。
还有一个论点是函数中的某些代码路径可能无法访问,但这可能不容易从简单的静态分析中确定,那么为什么强制执行不必要的void
?
答案 1 :(得分:9)
我猜它只是一个警告,因为编译器不能总是100%确定它可能不会返回。
即。如果你有:
-= source1.c =-
int func()
{
if(doSomething())
{
return 0;
}
}
-= source2.c =-
int doSomething()
{
return 1;
}
在这种情况下,编译器可能无法知道它总是会返回,但是你会这样做。当然,依靠了解外部代码的工作方式,这是一种糟糕的编程习惯。
至于实际返回的内容取决于平台。在x86 ABI上,EAX用于返回值(最多32位),因此它将返回放置在该寄存器中的内容(可能是来自其他内容的返回,临时值或总垃圾)。
答案 2 :(得分:6)
从技术上讲,如果调用函数并且该函数总是抛出异常,则不能保证会出错。例如,这里有一些伪代码,你知道raiseError总是抛出。
MyClass func( params )
{
if( allIsValid() )
{
return myObject;
}
else
{
raiseError( errorInfo );
}
}
如果编译器看不到raiseError的实现,则不会知道该函数是否会抛出。所以实际上这里确实没有未定义的行为。当然,在这里使编译器静音是很好的,你可以在raiseError之后写一个“虚拟”返回语句,或者使用虚拟“throw”。我把它们称为“虚拟”,因为它们永远不会实现。 (如果你真的坚持,你也可以取消警告)。但是没有错误或未定义的行为。
答案 3 :(得分:1)
这是另一个不是错误
的原因以下内容会给你相同的警告,因为编译器希望你从catch块返回一些东西,即使你扔掉那里
int foo(){
try{
return bar(0);
} catch(std::exception& ex){
//do cleanup
throw ex;
}
}
int bar(unsigned int i){
if(i == 0){
throw std::string("Value must be greater than 0");
} else{
return 0;
}
}
答案 4 :(得分:1)
另一个例子,某些控制路径可能没有返回值:
enum E : int {A, B};
int foo(E e) {
switch (e) {
case A: return 30;
case B: return 50;
}
}
e
可能不是A
或B
,但暗示它始终是其中一个值。如果是这样,那么代码很好,没有问题。将此警告变为强制性错误将需要不必要的“无法访问”的混乱。
如果您希望警告仍然是错误,您可以配置编译器使用/ WX或-Werror等标志来执行此操作。虽然你当然应该注意,不同的编译器可能会对不可达的内容做出不同的判断,因此你可能会为不同的编译器修复不同的东西。
答案 5 :(得分:-2)
这不是错误,因为它可能是预期的行为。例如,某些加密库使用未初始化的本地数据作为播种步骤。由于返回值保留在调用约定和特定于平台的位置,这可能有助于一些不寻常的(如上所述)情况。在这种情况下,函数返回用于返回返回值的寄存器上剩余的内容。
答案 6 :(得分:-2)
考虑以下情况:
UINT GenderID(GENDER gender)
{
switch(gender)
{
case MALE:
return MALE_ID;
case FEMALE:
return FEMALE_ID;
}
// default not required because [GENDER] in our 'Matrix' CAN be either M or F
}
C ++编译器应该让你让你的'Matrix'成为你的方式;这不是错误。