应使用哪个预处理器定义来指定代码的调试部分?使用#ifdef _DEBUG或#ifndef NDEBUG,或者是否有更好的方法,例如#define MY_DEBUG?我认为_DEBUG是Visual Studio特有的,NDEBUG是标准的吗?
#ifdef _DEBUG
#ifndef NDEBUG
#define MY_DEBUG
_DEBUG
s4n0splo1#
Visual Studio会在您指定/MTd或/MDd选项时定义_DEBUG,NDEBUG会停用标准C判断提示。请在适当的时候使用它们,例如,如果您希望两柴程式码与MS CRT debugging techniques一致,请使用_DEBUG;如果您希望与assert()一致,请使用NDEBUG。如果您定义了自己的调试宏(并且您没有修改编译器或C运行时),请避免以下划线开头,因为这些是保留名称。
/MTd
/MDd
NDEBUG
assert()
cvxl0en22#
NDEBUG是否为标准?是的,它是一个标准宏,语义为“未调试”,适用于C89、C99、C98、C2003、C2011、C2014标准。标准中没有_DEBUG宏。C++2003标准将读者在“第326页”处的“17.4.2.1 Headers”发送到标准C。NDEBUG类似于这与标准C库相同。在C89(C程序员称此标准为C标准)中的“4.2 DIAGNOSTICS”一节中有人说https://port70.net/~nsz/c/c89/c89-draft.html如果在源文件中包含的位置将NDEBUG定义为宏名称<assert.h>,则Assert宏仅定义为
#define assert(ignore) ((void)0)
如果查看Visual Studio https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros中_DEBUG宏的含义,则会发现此宏是由您选择的语言运行库版本自动定义的。
3pvhb19x3#
我依赖于NDEBUG,因为它是唯一一个在编译器和实现中行为标准化的(参见标准assert宏的文档)。负逻辑是一个小的可读性障碍,但它是一个常见的习惯用法,您可以很快适应它。依赖于_DEBUG这样的东西就是依赖于特定编译器和库实现的实现细节。其他编译器可能会也可能不会选择相同的约定。第三种选择是为项目定义自己的宏,这是非常合理的。拥有自己的宏可以在实现之间提供可移植性,并允许您独立于Assert启用或禁用调试代码。尽管如此,一般来说,我建议不要在编译时启用不同类的调试信息,因为它会导致您必须构建(和测试)的配置数量的增加,而这一点可以说是微不足道的。使用这些选项中的任何一个时,如果您使用第三方代码作为项目的一部分,则必须了解它使用的约定。
lkaoscv74#
宏NDEBUG控制assert()语句是否处于活动状态。在我看来,这是独立于任何其他调试的--所以我使用NDEBUG以外的东西来控制程序中的调试信息。不同的系统有不同的启用宏,我使用任何合适的宏。如果没有框架,我会使用没有前导下划线的名称;这些都倾向于保留给“实现”,我试图避免名称冲突的问题--当名称是宏时更是如此。
bksxznpy5#
保持一致性,不管是哪一个。而且,如果出于某种原因,你必须使用某个DEBUG标识符与另一个程序或工具互操作,这很容易做到
#ifdef THEIRDEBUG #define MYDEBUG #endif //and vice-versa
mzmfm0qo6#
不幸的是,DEBUG过载严重。例如,建议总是为RELEASE版本生成并保存一个pdb文件。这意味着-Zx标志之一,以及-DEBUG链接器选项。而_DEBUG与运行时库的特殊调试版本有关,如对malloc和free的调用。那么NDEBUG将禁用Assert。
DEBUG
-Zx
-DEBUG
malloc
free
ujv3wf0j7#
不管名称如何,NDEBUG与您是否创建调试版本无关,它控制Assert是否(assert())是活动的还是不活动的。我不会基于它做任何其他的事情,因为您有时可能希望拥有不带Assert的调试版本或带有Assert的发布版本,然后必须相应地设置NDEBUG,但这并不这并不意味着您还希望调试或发布所有其他代码。从编译器的Angular 来看,调试版本是不存在的。你告诉编译器用一组特定的设置来编译代码,如果你想对不同类型的版本使用不同的设置,那么这实际上是你自己创造的,编译器对此一无所知。你实际上可能有50种不同的构建风格,而不仅仅是发布和调试(profile、test、deploy等),所以如何在你自己的代码中标识这些样式取决于你。如果你需要这些样式的预处理器标记,你可以定义它们的命名方式,并且相同的命名空间规则适用于你在代码中定义的所有其他样式。
7条答案
按热度按时间s4n0splo1#
Visual Studio会在您指定
/MTd
或/MDd
选项时定义_DEBUG
,NDEBUG
会停用标准C判断提示。请在适当的时候使用它们,例如,如果您希望两柴程式码与MS CRT debugging techniques一致,请使用_DEBUG
;如果您希望与assert()
一致,请使用NDEBUG
。如果您定义了自己的调试宏(并且您没有修改编译器或C运行时),请避免以下划线开头,因为这些是保留名称。
cvxl0en22#
NDEBUG是否为标准?
是的,它是一个标准宏,语义为“未调试”,适用于C89、C99、C98、C2003、C2011、C2014标准。标准中没有
_DEBUG
宏。C++2003标准将读者在“第326页”处的“17.4.2.1 Headers”发送到标准C。
NDEBUG类似于这与标准C库相同。
在C89(C程序员称此标准为C标准)中的“4.2 DIAGNOSTICS”一节中有人说
https://port70.net/~nsz/c/c89/c89-draft.html
如果在源文件中包含的位置将NDEBUG定义为宏名称<assert.h>,则Assert宏仅定义为
如果查看Visual Studio https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros中
_DEBUG
宏的含义,则会发现此宏是由您选择的语言运行库版本自动定义的。3pvhb19x3#
我依赖于
NDEBUG
,因为它是唯一一个在编译器和实现中行为标准化的(参见标准assert宏的文档)。负逻辑是一个小的可读性障碍,但它是一个常见的习惯用法,您可以很快适应它。依赖于
_DEBUG
这样的东西就是依赖于特定编译器和库实现的实现细节。其他编译器可能会也可能不会选择相同的约定。第三种选择是为项目定义自己的宏,这是非常合理的。拥有自己的宏可以在实现之间提供可移植性,并允许您独立于Assert启用或禁用调试代码。尽管如此,一般来说,我建议不要在编译时启用不同类的调试信息,因为它会导致您必须构建(和测试)的配置数量的增加,而这一点可以说是微不足道的。
使用这些选项中的任何一个时,如果您使用第三方代码作为项目的一部分,则必须了解它使用的约定。
lkaoscv74#
宏
NDEBUG
控制assert()
语句是否处于活动状态。在我看来,这是独立于任何其他调试的--所以我使用
NDEBUG
以外的东西来控制程序中的调试信息。不同的系统有不同的启用宏,我使用任何合适的宏。如果没有框架,我会使用没有前导下划线的名称;这些都倾向于保留给“实现”,我试图避免名称冲突的问题--当名称是宏时更是如此。
bksxznpy5#
保持一致性,不管是哪一个。而且,如果出于某种原因,你必须使用某个DEBUG标识符与另一个程序或工具互操作,这很容易做到
mzmfm0qo6#
不幸的是,
DEBUG
过载严重。例如,建议总是为RELEASE版本生成并保存一个pdb文件。这意味着-Zx
标志之一,以及-DEBUG
链接器选项。而_DEBUG
与运行时库的特殊调试版本有关,如对malloc
和free
的调用。那么NDEBUG
将禁用Assert。ujv3wf0j7#
不管名称如何,
NDEBUG
与您是否创建调试版本无关,它控制Assert是否(assert()
)是活动的还是不活动的。我不会基于它做任何其他的事情,因为您有时可能希望拥有不带Assert的调试版本或带有Assert的发布版本,然后必须相应地设置NDEBUG
,但这并不这并不意味着您还希望调试或发布所有其他代码。从编译器的Angular 来看,调试版本是不存在的。你告诉编译器用一组特定的设置来编译代码,如果你想对不同类型的版本使用不同的设置,那么这实际上是你自己创造的,编译器对此一无所知。你实际上可能有50种不同的构建风格,而不仅仅是发布和调试(profile、test、deploy等),所以如何在你自己的代码中标识这些样式取决于你。如果你需要这些样式的预处理器标记,你可以定义它们的命名方式,并且相同的命名空间规则适用于你在代码中定义的所有其他样式。