在查看工作代码时,我发现了一些(看似)令人反感的代码,其中函数具有返回类型,但没有返回.我知道代码有效,但认为它只是编译器中的一个错误.
我编写了以下测试并使用我的编译器运行它(gcc(Homebrew gcc 5.2.0)5.2.0)
#include <stdio.h>
int f(int a, int b) {
int c = a + b;
}
int main() {
int x = 5, y = 6;
printf("f(%d,%d) is %d\n", x, y, f(x,y)); // f(5,6) is 11
return 0;
}
Run Code Online (Sandbox Code Playgroud)
类似于我在工作中发现的代码,这默认返回函数中执行的最后一个表达式的结果.
我发现了这个问题,但对答案不满意.我知道-Wall -Werror可以避免这种行为,但为什么它是一个选项呢?为什么这仍然允许?
Bau*_*gen 12
"为什么这仍然允许?" 它不是,但一般来说,编译器无法证明你正在这样做.考虑这个(当然非常简化)示例:
// Input is always true because logic reason
int fun (bool b) {
if (b) {
return 7;
}
}
Run Code Online (Sandbox Code Playgroud)
甚至这个:
int fun (bool b) {
if (b) {
return 7;
}
// Defined in a different translation unit, will always call exit()
foo();
// Now we can never get here, but the compiler cannot know
}
Run Code Online (Sandbox Code Playgroud)
现在第一个例子可以从最后流出,但只要函数"正确"使用它就永远不会; 而第二个不能,但编译器不能知道这一点.所以编译器会破坏"工作"和合法,尽管可能是愚蠢的代码,因为这是一个错误.
现在你发布的例子有点不同:这里,所有路径都流出端,所以编译器可以拒绝或者忽略这个函数.然而,它会破坏依赖于生产代码中的编译器特定行为的真实世界代码,并且人们不喜欢它,即使它们是错误的.
但最终,流出非void功能的结尾仍然是未定义的行为.它可能适用于某些编译器,但它不是,也绝不保证.
这不是编译器中的错误,但代码显然格式错误。在 x86 架构上,(R|E)AX 用作累加器寄存器和返回值。
你会看到 for 的代码f()确实使用 eax 来存储加法结果。
但是......继续使用-O1(或任何更激进的优化级别)作为编译器选项(右上角的框),看看现在会发生什么。
...我们发现编译器正确地意识到该函数没有显式返回其结果,它只是变成了一个空操作。
因此,这段令人讨厌的代码是一个完美的例子,它可以像调试版本一样工作,但在应用任何优化时都会失败。
| 归档时间: |
|
| 查看次数: |
9820 次 |
| 最近记录: |