好吧,我用C ++编译器发现的一点奇怪。
我有一个不太复杂的代码重构,我不小心设法离开了一条没有返回语句的路径。我的错。另一方面,当我运行它并且该路径被击中时,这编译并发生了分段。显然。
这是我的问题:这是一个编译器错误,还是不能保证C ++编译器会在非void返回函数中强制需要return语句?
哦,并且要明确,在这种情况下,如果没有附带的其他声明,这是一个不必要的声明。没有任何东西,没有退出,没有中止。
答案 0 :(得分:13)
无法保证C ++编译器会强制执行该操作。 C ++函数可能会被编译器未知的机制跳出其控制流。使用C ++编写OS内核时的上下文切换就是一个例子。被调用函数抛出的未捕获异常(其代码不一定对调用者可用)是另一个异常。
其他一些语言(如Java)明确强制执行,在编译时可用的知识,所有路径都返回一个值。在C ++中,这不是正确的,就像语言中的许多其他场合一样,也不会检查从其边界中访问数组。
答案 1 :(得分:11)
我个人认为这应该是一个错误:
int f() {
}
int main() {
int n = f();
return 0;
}
但是大多数编译器将其视为警告,您甚至可能必须使用编译器开关来获取警告。例如,在g ++上你需要-Wall得到:
[neilb@GONERIL NeilB]$ g++ -Wall nr.cpp
nr.cpp: In function 'int f()':
nr.cpp:2: warning: no return statement in function returning non-void
当然,使用g ++,你总是应该至少使用-Wall进行编译。
答案 2 :(得分:4)
编译器不强制执行此操作,因为您了解编译器实际上不可能使用哪些路径。编译器通常只知道该特定文件,而不知道可能影响任何给定函数内的流的其他文件。所以,这不是错误。
但在Visual Studio中,这是一个警告。我们应该注意所有警告......对吗? :)
修改强>: 似乎有一些关于何时会发生这种情况的讨论。这是我个人代码库中经过修改但真实的示例;
enum TriBool { Yes, No, Maybe };
TriBool GetResult(int input) {
if (TestOne(input)) {
return Yes;
} else if (TestTwo(input)) {
return No;
}
}
请耐心等待,因为这是旧代码。最初在那里有一个“别的回归”。 :)如果TestOne和TestTwo位于不同的编译单元中,那么当编译器遇到此代码时,它无法判断TestOne和TestTwo是否都可以为给定的输入返回false。作为编写TestOne和TestTwo的程序员,您知道如果TestOne失败,那么TestTwo将成功。也许这些测试有副作用,所以他们必须完成。没有“else if”写它会更好吗?也许。大概。但关键是这是合法的C ++,并且编译器无法知道是否可以在没有return语句的情况下退出。它是,我同意,丑陋而不是很好的编码,但它是合法的,Visual Studio会给你一个警告,但它会编译。
请记住,C ++并不是要保护自己。它是关于让你在语言的限制下做你的心所欲望的事情,即使这包括在脚下射击自己。