让我们看一下这段代码:
#include <iostream>
int foo(int i) {return i; }
int foobar(int z) {return foo(z);}
int main() {
std::cout << foobar(3) << std::endl;
}
用g ++ -std = c ++ 11编译好...并给出输出3.但相同的输出由下式给出:
#include <iostream>
int foo(int i) {return i; }
int foobar(int z) { foo(z);}
int main() {
std::cout << foobar(3) << std::endl;
}
它没有问题编译,但很明显foobar错过了关键字返回。这是gcc 4.8.3中的错误还是我不知道某些c ++ 11原则? (在Fedora 20上运行)
答案 0 :(得分:6)
C ++标准没有要求编译器在函数返回非return
中坚持void
- 语句。相反,在没有return
语句的情况下流出这样一个函数的结尾是未定义的行为。标准中的相关陈述在6.6.3 [stmt.return]第2段,最后一句(以及在3.6.1 [basic.start.main]第5段中的陈述是main()
可以流动的陈述关闭此功能):
离开函数末尾相当于没有值的返回;这会导致值返回函数中的未定义行为。
这种方法的主要原因是,如果函数实际上真的返回,它可能是非平凡的,甚至是不可能的。考虑这个函数声明和函数定义:
extern void will_always_throw();
int does_not_return_anything() {
will_always_throw();
}
假设will_always_throw()
确实如顾名思义所做,那就没有错。事实上,如果编译器变得更聪明并且设法验证will_always_throw()
,确实总是抛出(或者“noreturn”属性附加到will_always_throw()
,它可能会警告此定义中的最后一个语句永远不会到达:
int does_return_something_just_in_case() {
will_always_throw();
return 17;
}
处理这些情况的一般方法是编译器支持在必要时启用/禁用警告的适当选项。例如,在您的代码中,我有权访问的所有编译器(gcc
,clang和icc
)会在启用警告时创建警告(前两个使用-Wall
和-w2
用于英特尔的编译器。)
答案 1 :(得分:4)
代码编译得很好,因为它是格式良好的,所以你可以运行它。但由于这是未定义的行为,你不能依赖程序的任何行为,任何事情都是合法的。为防止此类事故,请启用编译器警告。如果您使用-Wall
编译代码,则会看到
main.cpp:10:28: warning: no return statement in function returning non-void [-Wreturn-type]
int foobar(int z) { foo(z);}
Here您可以获得有关这些警告的更多信息。使用它们并确保您的代码免费编译警告。它可以在编译时捕获代码中很多的错误。