__builtin_unreachable()
在GCC 7.3.0上没有生成任何编译时警告
我在文档中也没有找到任何关于此的说明。
例如,以下示例将编译而无需任何警告:
#include <stdio.h>
int main(void) {
__builtin_unreachable();
puts("hello")
return 0;
}
使用:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -Wunreachable-code main.c
我认为它唯一能做到的是,让编译器根据某行代码永远不被执行这个事实来进行某些优化,并在您出现编程错误并且该行代码确实被执行时给出未定义行为。
例如,执行上面的示例似乎正常退出,但没有像预期的那样打印 hello
。我们的汇编分析随后显示,正常看起来的退出实际上只是一个偶然的未定义行为。
GCC 的 -fsanitize=unreachable
标志将 __builtin_unreachable();
转换为在运行时失败的断言:
<stdin>:1:17: runtime error: execution reached a __builtin_unreachable() call
然而在Ubuntu 16.04中,该标志已经失效:ld: unrecognized option '--push-state--no-as-needed'
__builtin_unreachable()
对可执行文件有什么影响?
如果我们使用__builtin_unreachable
来反汇编代码:
objdump -S a.out
我们可以看到没有它的时候调用了
puts
函数:
000000000000063a <main>:
#include <stdio.h>
int main(void) {
63a: 55 push %rbp
63b: 48 89 e5 mov %rsp,%rbp
puts("hello")
63e: 48 8d 3d 9f 00 00 00 lea 0x9f(%rip),%rdi # 6e4 <_IO_stdin_used+0x4>
645: e8 c6 fe ff ff callq 510 <puts@plt>
return 0
64a: b8 00 00 00 00 mov $0x0,%eax
}
64f: 5d pop %rbp
650: c3 retq
651: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
658: 00 00 00
65b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
只有带有它的那个执行:
而没有它的那个不执行:
int main(void) {
5fa: 55 push %rbp
5fb: 48 89 e5 mov %rsp,%rbp
5fe: 66 90 xchg %ax,%ax
甚至没有返回,所以我认为它只是一种未定义的行为巧合,它没有崩溃。
为什么GCC不能确定某些代码是否不可达?
我收集了以下答案:
determining unreachable code automatically is too hard for GCC for some reason, which is why for years now -Wunreachable-code
does nothing: gcc does not warn for unreachable code
users may use inline assembly that implies unreachability, but GCC cannot determine that. This is mentioned on the GCC manual:
One such case is immediately following an asm statement that either never terminates, or one that transfers control elsewhere and never returns. In this example, without the __builtin_unreachable, GCC issues a warning that control reaches the end of a non-void function. It also generates code to return after the asm.
int f (int c, int v)
{
if (c)
{
return v;
}
else
{
asm("jmp error_handler");
__builtin_unreachable ();
}
}
在GCC 7.3.0和Ubuntu 18.04上进行了测试。
__builtin_unreachable()
似乎不能实现 OP 想要的功能,即在可达到的情况下在编译时中断。如果没有使用-fsanitize=unreachable
,即使代码在编译时被触发,它也不会默认断言,而是 UB。请参见:https://dev59.com/A3A75IYBdhLWcg3wSm64#52722868 - Ciro Santilli OurBigBook.com__builtin_unreachable()
之后有代码时发出警告。但是对于大多数代码,你通常会在这种情况下使用return
,对吧? - Ciro Santilli OurBigBook.com