编译器是否会删除条件始终为 false 的 if 语句?

问题描述 投票:0回答:2

我知道 C++ 中的一些元编程技术,可以在编译时计算常量。大多数情况下,元函数中的分支是通过三元运算符完成的,这些运算符可以在编译时进行计算,这与标准 if/else 相反。

但是对于这种功能:

template <unsigned int N>
void f()
{
    if (N == 0) {
        // Some computations here
    } else if (N <= 42) {
        // Some computations here
    } else {
        // Some computations here
    }
}

编译器会做什么(假设

-O3
)? 编译器知道
f<0>()
将始终在第一种情况下分支,
f<32>()
将始终在第二种情况下分支,而
f<64>()
将始终在第三种情况下分支。

编译器会删除那些永远是

false
的分支吗?会直接分支到唯一有效的case吗?

c++ if-statement c++11 compiler-optimization c++-templates
2个回答
7
投票

优化器将删除分支和未使用分支中的代码,但要注意:编译器需要在优化器有机会查看代码之前处理函数,这意味着所有分支都必须有效(可编译)

N
的所有值。

例如,如果第二个分支包含:

} else if (N <= 42) {
   char data[50 - N];
// other code

即使优化器会删除该分支,编译器也将无法实例化

N >= 50
的模板。


2
投票

我在 http://gcc.godbolt.org/ 中输入了以下内容,这是一个显示生成的程序集的在线编译器。您可以使用自己的编译器及其支持的任何开关来输出程序集。

volatile int i;

template <unsigned int N>
void f()
{
    if (N == 0) {
        i = 1;
    } else if (N <= 42) {
        i = 2;
    } else {
        i = 3;
    }
}

template void f<0>();
template void f<10>();
template void f<100>();

这是我得到的组件

void f<0u>():                           # @void f<0u>()
    movl    $1, i
    ret

void f<10u>():                          # @void f<10u>()
    movl    $2, i
    ret

void f<100u>():                         # @void f<100u>()
    movl    $3, i
    ret

i:
    .long   0                       # 0x0

如您所见,每个实例化都删除了所有死代码。

事实上,这段代码是在禁用优化的情况下生成的;我使用的编译器(clang)首先不会生成死代码的指令。其他编译器的行为可能有所不同。您必须自己测试自己的编译器的行为。

© www.soinside.com 2019 - 2024. All rights reserved.