【发布时间】:2011-01-18 10:20:04
【问题描述】:
应该使用哪个预处理器定义来指定代码的调试部分?
使用#ifdef _DEBUG 或#ifndef NDEBUG 或者有更好的方法,例如#define MY_DEBUG?
我认为_DEBUG 是 Visual Studio 特定的,是 NDEBUG 标准吗?
【问题讨论】:
应该使用哪个预处理器定义来指定代码的调试部分?
使用#ifdef _DEBUG 或#ifndef NDEBUG 或者有更好的方法,例如#define MY_DEBUG?
我认为_DEBUG 是 Visual Studio 特定的,是 NDEBUG 标准吗?
【问题讨论】:
Visual Studio 定义 _DEBUG 当您指定 /MTd 或 /MDd 选项时,NDEBUG 禁用标准 C 断言。在适当的时候使用它们,即_DEBUG,如果你希望你的调试代码与MS CRT debugging techniques一致,NDEBUG如果你想与assert()一致。
如果您定义自己的调试宏(并且您没有破解编译器或 C 运行时),请避免以下划线开头的名称,因为这些是保留的。
【讨论】:
NDEBUG 标准吗?
是的,它是一个标准宏,具有 C89、C99、C++98、C++2003、C++2011、C++2014 标准的语义“非调试”。标准中没有 _DEBUG 宏。
C++2003 标准在“17.4.2.1 Headers”的“page 326”发送阅读器 到标准C。
NDEBUG 类似于 This is the same as the Standard C library。
在 C89(C 程序员将此标准称为标准 C)中的“4.2 DIAGNOSTICS”部分中这样说
http://port70.net/~nsz/c/c89/c89-draft.html
如果 NDEBUG 在源文件中被定义为宏名 包含在哪里,断言宏被简单地定义为
#define assert(ignore) ((void)0)
如果看Visual Studio中_DEBUG宏的含义
https://msdn.microsoft.com/en-us/library/b0084kay.aspx
然后会看到,这个宏是由您选择的语言运行时库版本自动定义的。
【讨论】:
我依赖NDEBUG,因为它是唯一一个其行为跨编译器和实现标准化的工具(请参阅标准断言宏的文档)。否定逻辑是一个小的可读性减速带,但它是您可以快速适应的常见习语。
依赖_DEBUG 之类的东西将依赖于特定编译器和库实现的实现细节。其他编译器可能会也可能不会选择相同的约定。
第三种选择是为你的项目定义自己的宏,这是相当合理的。拥有自己的宏为您提供了跨实现的可移植性,它允许您独立于断言启用或禁用调试代码。不过,总的来说,我建议不要在编译时启用不同类别的调试信息,因为它会导致您必须构建(和测试)的配置数量增加,而收益可能很小。
使用这些选项中的任何一个,如果您在项目中使用第三方代码,则必须知道它使用哪种约定。
【讨论】:
#if !defined(NDEBUG) #if 不是 #ifdef?
#ifdef NDEBUG ...但是要特别注意 #if !defined(NDEBUG) 的否定逻辑。否则很难捕捉到 #ifndef NDEBUG 中的 n"
宏 NDEBUG 控制 assert() 语句是否处于活动状态。
在我看来,这与任何其他调试都是分开的——所以我使用NDEBUG 以外的东西来控制程序中的调试信息。我使用的内容会有所不同,具体取决于我正在使用的框架;不同的系统有不同的启用宏,我使用合适的。
如果没有框架,我会使用没有前导下划线的名称;这些往往保留给“实现”,我尽量避免出现名称冲突的问题——当名称是宏时更是如此。
【讨论】:
#if 控制的代码放在另一类中不同。 assert(huge_object.IsValid()); 可能会很慢,而 assert(ptr != nullptr); 可能不会。我同意 Jonathan 的观点,即 logging 和 tracing 可能应该不同于断言,至少在大型项目中是这样,但我不认为 logging或 tracing 作为调试代码,这就是我要求澄清的原因。
保持一致,不管是哪一个。此外,如果由于某种原因您必须使用某个 DEBUG 标识符与另一个程序或工具进行互操作,这很容易做到
#ifdef THEIRDEBUG
#define MYDEBUG
#endif //and vice-versa
【讨论】:
不幸的是DEBUG 严重超载。例如,建议始终为 RELEASE 构建生成并保存 pdb 文件。这意味着-Zx 标志和-DEBUG 链接器选项之一。而_DEBUG 与运行时库的特殊调试版本有关,例如对malloc 和free 的调用。然后NDEBUG 将禁用断言。
【讨论】: