1

让我们看一下这样的代码:

#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 中缺少关键字 return。它是 gcc 4.8.3 中的错误还是我不知道某些 c++11 原则?(在 Fedora 20 上运行)

4

2 回答 2

6

C++ 标准没有强制编译器return在函数 return non- 中坚持使用 - 语句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;
}

处理这些情况的一般方法是让编译器根据需要支持适当的选项启用/禁用警告。例如,在您的代码上,我有权访问的所有编译器(gccclangicc)都会创建一个警告,假设警告已启用(-Wall用于前两个和-w2英特尔的编译器)。

于 2014-12-14T22:14:06.523 回答
4

该代码编译良好,因为它格式正确,因此您可以运行它。但由于这是未定义的行为,您不能依赖程序的任何行为,任何事情都是合法的。为防止发生此类事故,请启用编译器警告。如果你用 编译你的代码-Wall,你会看到

main.cpp:10:28: warning: no return statement in function returning non-void [-Wreturn-type]
 int foobar(int z) { foo(z);}

在这里,您可以获得有关这些警告的更多信息。使用它们并确保您的代码编译无警告。它可以在编译时捕获代码中的许多错误。

于 2014-12-14T21:58:59.010 回答