C++ 没有返回语句时的叮当声优化:是否输入(false)?
下面是一个小的工作代码:C++ 没有返回语句时的叮当声优化:是否输入(false)?,c++,optimization,clang,clang++,C++,Optimization,Clang,Clang++,下面是一个小的工作代码: #include <iostream> #include <string> std::string f(int i) { if (i == 0) return "zero"; if (i == 1) return "one"; } int main(int argc, char const *argv[]) { (void)argv; std::cout << "Passed " <<
#include <iostream>
#include <string>
std::string f(int i) {
if (i == 0)
return "zero";
if (i == 1)
return "one";
}
int main(int argc, char const *argv[]) {
(void)argv;
std::cout << "Passed " << f(argc - 1) << " arguments." << std::endl;
return 0;
}
好吧,这显然是意料之中的
现在,通过优化进行编译:
$ clang++ ./return_optims_ifs.cpp -o test
./return_optims_ifs.cpp:10:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
1 warning generated.
$ ./test
Passed zero arguments.
$ ./test a
Passed one arguments.
$ ./test a b
[1] 20447 illegal hardware instruction (core dumped) ./test a b
$ clang++ ./return_optims_ifs.cpp -o test -O3
./return_optims_ifs.cpp:10:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
1 warning generated.
$ ./test
Passed zero arguments.
$ ./test a
Passed one arguments.
$ ./test a b
Passed one arguments.
等等,什么
什么样的优化可以假设我希望最后一个if()是“默认情况”
我怎样才能禁用这个optim,真正看到由于错误代码导致的崩溃,而不是让它们隐藏起来
$ clang --version
clang version 4.0.1 (tags/RELEASE_401/final)
Target: x86_64-unknown-linux-gnu
编译器优化强烈依赖于体系结构版本 不过,我想我仍然可以回答你的问题 您可以看到一个在线反汇编(使用Clang4.0.1)
f
功能将按以下方式分解:
f[abi:cxx11](int): # @f[abi:cxx11](int)
lea rax, [rdi + 16]
mov qword ptr [rdi], rax
test esi, esi
je .LBB0_1 // <=== JUMP NOT EQUAL
mov byte ptr [rax + 2], 101
mov word ptr [rax], 28271
mov qword ptr [rdi + 8], 3
mov byte ptr [rdi + 19], 0
mov rax, rdi
ret
.LBB0_1:
mov dword ptr [rdi + 16], 1869768058
mov qword ptr [rdi + 8], 4
mov byte ptr [rdi + 20], 0
mov rax, rdi
ret
这就是为什么你可能会得到意想不到的结果。您的“ab”
输入将执行案例2!=0
返回“一”
重要提示
非常重要的是要考虑代码产生了一个未定义的行为。这意味着代码的行为可以是任何东西。在另一个编译器/体系结构上,输出结果可能不同
必须极力避免这种代码。编译器的优化强烈依赖于体系结构版本 不过,我想我仍然可以回答你的问题 您可以看到一个在线反汇编(使用Clang4.0.1)
f
功能将按以下方式分解:
f[abi:cxx11](int): # @f[abi:cxx11](int)
lea rax, [rdi + 16]
mov qword ptr [rdi], rax
test esi, esi
je .LBB0_1 // <=== JUMP NOT EQUAL
mov byte ptr [rax + 2], 101
mov word ptr [rax], 28271
mov qword ptr [rdi + 8], 3
mov byte ptr [rdi + 19], 0
mov rax, rdi
ret
.LBB0_1:
mov dword ptr [rdi + 16], 1869768058
mov qword ptr [rdi + 8], 4
mov byte ptr [rdi + 20], 0
mov rax, rdi
ret
这就是为什么你可能会得到意想不到的结果。您的“ab”
输入将执行案例2!=0
返回“一”
重要提示
非常重要的是要考虑代码产生了一个未定义的行为。这意味着代码的行为可以是任何东西。在另一个编译器/体系结构上,输出结果可能不同
必须极力避免使用这种代码
什么样的优化可以假设我希望最后一个if()是“默认情况”
您的函数必须返回一个值,因为签名是这样写的
从源代码中我们可以看到选项是返回“零”
和返回“一”
。因此,如果它不是“零”,那么它必须是“一”,因为没有更多的选择
唯一的其他选择是你的程序无效。但这是不允许的,所以不可能发生,对吗?至少优化器可能会假设它从未发生过
什么样的优化可以假设我希望最后一个if()是“默认情况”
您的函数必须返回一个值,因为签名是这样写的
从源代码中我们可以看到选项是返回“零”
和返回“一”
。因此,如果它不是“零”,那么它必须是“一”,因为没有更多的选择
唯一的其他选择是你的程序无效。但这是不允许的,所以不可能发生,对吗?至少优化器可能会假设它从未发生过。这是未定义的行为,如果达到第二个
如果
,则它必须为真,否则它将是未定义的行为。因此,编译器可以优化if
并在第一个if
为false时返回“one”
。编译器会警告您这一点。你还想要什么?什么说代码必须崩溃?编译器会警告您未定义的行为,这足以告诉您需要修复代码,它甚至会告诉您在哪里。您可以使用-Werror
强制它也成为错误。它已经在编译时警告您,您还想要什么?停止对UB的特定行为的期望。一旦您使用未定义的行为,编译器可以执行的操作就没有限制。如果它选择的话,它可以格式化你的硬盘,而且它仍然与ISO标准兼容。事实上,我只是期望与调试相同的行为:崩溃。考虑到情况并非如此,这就好像优化是不可靠的。但无论如何,我可以在这里看到UB问题。这是未定义的行为,如果达到第二个如果,它必须是真的,否则它将是未定义的行为。因此,编译器可以优化if
并在第一个if
为false时返回“one”
。编译器会警告您这一点。你还想要什么?什么说代码必须崩溃?编译器会警告您未定义的行为,这足以告诉您需要修复代码,它甚至会告诉您在哪里。您可以使用-Werror
强制它也成为错误。它已经在编译时警告您,您还想要什么?停止对UB的特定行为的期望。一旦您使用未定义的行为,编译器可以执行的操作就没有限制。如果它选择的话,它可以格式化你的硬盘,而且它仍然与ISO标准兼容。事实上,我只是期望与调试相同的行为:崩溃。考虑到情况并非如此,这就好像优化是不可靠的。但无论如何,我可以看到UB的问题。好的,我可以看到会发生什么。顺便说一句,如果我只有第一个if(),那么函数将返回“one”。如果它是单独的,那么“如果”就被省略了。好吧,我可以看到会发生什么。顺便说一句,如果我只有第一个if(),那么函数将返回“one”。因此,如果“if”是单独的,那么它就被省略了。函数并不总是返回值(想想throw或exit)。这是人们所期望的行为,就像没有优化时一样。函数并不总是返回值(想想throw或exit)。这是人们所期望的行为,就像没有优化时发生的那样。