编译器开关或预处理器开关

Compiler switch or preprocessor switch?

本文关键字:开关 处理器 预处理 编译器      更新时间:2023-10-16

使用预处理器切换代码非常常见:

#define MY_SWITCH (1)
#if MY_SWITCH
   cout << "on" << Test(1);
#else
   cout << "off" << Test(2);
#endif

但是,如果该代码段外的代码发生了更改(例如,如果重命名了Test()函数),则禁用的行可能会因为未编译而保持过时。

我想使用一种不同的开关来完成这项工作,让代码在每次构建时都被编译,这样我就可以立即找到过时的行。例如:

static const bool mySwitch = true;
if (mySwitch)
{
   cout << "on" << Test(1);
}
else
{
   cout << "off" << Test(2);
}

然而,我需要防止这种方法消耗额外的资源。是否有任何保证(或可靠的假设)现代C++编译器将删除非活动分支(例如使用优化)?

就在几周前,我遇到了这个问题—在我的代码库中禁用一个有问题的诊断功能表明,替代代码中有一些新的错误,阻碍了编译。不过,我不会按照你的建议行事。

您首先牺牲了使用宏的好处,而不一定会获得任何好处。我希望我的编译器能优化死分支,但你不能依赖它我觉得宏方法让你的程序有两种不同的"配置"变得更加明显,在特定的构建中只能使用一种。

我会让您的持续集成系统(或驱动自动构建测试的任何系统)在构建配置的各种组合中循环(在命令行上使用-D提供宏,可能来自Makefile或其他构建脚本,而不是在源代码中对它们进行硬编码),并对它们进行全部测试

对于编译器优化,您没有保证。(如果您想要经过验证的C优化,请查看compcert)。

然而,在这种情况下,大多数编译器都会进行优化,有些编译器甚至可能会对死代码发出警告。尝试使用最近启用了优化的GCC或Clang/LLVM(例如g++ -Wall -Wextra -O2)。

此外,我相信大多数编译器在生成优化代码的执行时不会消耗资源,但在编译时会消耗资源。

也许使用constexpr可以帮助某些编译器更好地进行优化。

此外,查看生成的汇编代码(例如使用g++ -O2 -fverbose-asm -S)或编译器的中间转储(例如g++ -O2 -fdump-tree-all,它提供了数百个的转储文件)。如果使用GCC,您可以使用MELT对其进行自定义,例如添加额外的编译时检查。