我一直在阅读有关条件编译的最佳实践,但是我还没有找到关于这种情况的例子。
我有一个C项目,其目标平台是特定的设备(与PC不同)。我有一个仅包含集成测试功能之类的源文件。我希望仅在DEBUG
个版本中而不是在RELEASE
个版本中编译和链接此文件。
我的问题是,以下哪个选项是更好的做法:
一个*.c
文件,如下所示:
Tests.c
---------
#ifndef NDEBUG
// All testing functions
...
#endif
并将该文件包含在DEBUG
和RELEASE
的版本中。
或
检查是否在项目的NDEBUG
中定义了Makefile / CMakeLists.txt
,并因此包括了提到的源文件。
答案 0 :(得分:6)
我对此的个人看法(!):
首选第一种方法-#ifndef NDEBUG
。
开始时有cc *.c
。
然后添加了适当的选项。
随后出现了构建系统,该系统找出了实际上{em>需要重新编译的*.c
个文件中的哪个,并使您无需记住哪些合适的选项。 / p>
然后是更复杂的构建系统,可以为您找到合适的选择。
随着时间的流逝,构建系统变得越来越智能,并且可以拥有重要的逻辑。但是,我认为这种智能应该继续专注于其主要功能(请参见上文),并且最终cc *.c
仍在发挥作用。
构建系统已过时或被替换。下一个人甚至可能都不知道您选择的构建系统;他仍然应该能够在项目中脱颖而出,而不必深入研究构建系统的逻辑。
设置/检查NDEBUG
为C,只要对该语言(和<assert.h>
)有较深的了解,任何人都会立即识别出您打算在该语言中做什么。
弄清楚为什么特定的源文件仅应包含在构建系统中的特定构建类型中,而不应包含在其他构建类型中,这不是那么直观,并且在有人上手时可能会完全迷失,扔掉您的{{1} },因为他更喜欢Jam并从头开始构建。该人可能最终想知道为什么所有这些测试都会使他的发行代码混乱,以及为什么您不够聪明,无法将其设置为“仅调试”(没有意识到您 did 在构建系统中做到了)
答案 1 :(得分:1)
实际上,我不明白为什么只选择一个?我认为,这两个选项可以和应一起使用。
如果在发行版本中完全不需要某些文件,则完全有理由将其完全排除在构建过程之外。但是在源代码中有一些预处理器防护(无论是#ifdef
还是#error
)都是非常有用的。
答案 2 :(得分:0)
我相信第一种方法(#ifndef NDEBUG
)更好,为什么?
因为我相信每个代码封装或依赖项都应在尽可能最低的级别上执行。如果构建系统可以继续工作而又不知道该文件仅针对DEBUG构建进行编译,那么我们已经成功删除了项目中的依赖项。
在最后一个参数的基础上,如果将来其他项目需要此文件,则将有两个地方有条件地运行,而不是一个地方。