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)。这是人们所期望的行为,就像没有优化时发生的那样。