编译器开关或预处理器开关
Compiler switch or preprocessor switch?
使用预处理器切换代码非常常见:
#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对其进行自定义,例如添加额外的编译时检查。
- #定义c-预处理器常量..我做错了什么
- 预处理器:插入结构名称中的前一个行号
- 如何在c++中实现处理器调度模拟器
- 既然存在危险,为什么项目要使用-I include开关
- C/C++预处理器是否可以检测一些编译器选项
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 为什么这个音频包络不能通过开关的情况?
- 在clang++预处理器中确定gcc工具链版本
- 不同/较旧的处理器运行c++代码的方式是否不同
- 有人知道为什么在开关中使用stoi函数会返回恒定的错误吗
- 用于交叉编译和CMake的预处理器宏的单元测试
- C 和 C++ 中开关语句的案例标签的常量值,但显示不同的行为
- 有没有办法在从编译器获取参数时避免预处理器宏?
- 在 c++ 中在开关情况下使用和不使用"break"时的不同输出
- 如何比较两个同名的预处理器宏?
- 为什么我的开关/机箱在使用枚举时默认?
- 从预处理器获取 Windows 版本(C++ Win32)
- 如何摆脱为条件编译定义预处理器宏的需要?
- 是C 库中必需的基于预处理器的功能开关
- 编译器开关或预处理器开关