调试宏与调试变量
Debug macro vs. Debug variable
下面是一个使用调试变量的例子
class A{
public:
A(bool debug):m_debug(debug){};
~A(){};
void Test(){
for(int i=0;i<1000000;i++){
// do something
if(m_debug) print();
}
}
void print(){
std::cout << "something" << std::endl;
}
private:
bool m_debug;
};
下面是使用调试宏预处理器的示例
#include "Preprocessor.h"
class A{
public:
void Test(){
for(int i=0;i<1000000;i++){
// do something
#ifdef DEBUG
print();
#endif
}
}
void print(){
std::cout << "something" << std::endl;
}
};
在Preprocessor.h中就是
#define DEBUG
使用调试变量的好处是 class 减少了对全局预处理器头文件的依赖。宏方法的好处是在 运行 时间执行的 if 语句少了 1000000 条,这对于假设每个 fps 都很重要的图形应用程序来说可能是至关重要的。什么会被认为是更好的方法?
更好的方法是使用预处理器,但是,它不需要新的头文件来定义宏。
您可以在编译时设置标志,使用 -DMACRO_NAME
或者,在您的情况下,-DDEBUG
。
首先,宏方法在内存和测试方面都更好(尽管这确实是很小的成本)。你有什么特殊场景需要使用debug变量吗?
为什么不在 CPP 文件中定义 A::Test()?因此全局预处理器 header 可以移动到 CPP 文件中。无论如何,我不认为在 header 中公开此类调试细节是个好主意。
另一种选择,如果您不喜欢一堆#ifdef DEBUG / #endif 行,您可以创建一个宏来输出它的参数(如果已定义)(很像 assert 宏)。
#ifdef DEBUG
#define PRINT(x) (x)
#else
#define PRINT(x)
#endif
PRINT( std::cout << "something" << std::endl );
只要作业正在打印调试信息,先例就是使用像 Visual Studio 那样的宏(debug/release 构建)。但是在 Qt 世界中,有 class QLoggingCatagory
可以在其中 enable/disable 记录部分。每次注销消息时,它都会调用函数 QLoggingCategory::isDebugEnabled()
,这让我认为至少对于正常使用来说,这不是性能的主要问题。
也就是说,如果我们将 Visual Studio MFC 应用程序与 Qt 应用程序进行比较,MFC 应用程序速度很快。这至少可以部分归因于它使用宏,并且在调试和发布版本中可以很容易地注意到差异,其中 macro/debug 信息是主要差异。
鉴于所有这些证据,我投票支持在您的情况下使用宏方法以获得最佳性能。
代码路径并不比 "compiled away" 更小。但是,如果您愿意执行重构步骤,则可以以更大的可执行文件为代价使 run-time 调试版本更便宜。
想法是使调试状态成为 Test()
重构版本的模板参数,以便它可能会或可能不会在每次迭代时打印调试语句。如果 false
被传递给模板,编译器的死代码消除过程将优化语句,因为模板参数将被视为模板扩展中的编译时间常量。
当然,完全优化的版本仍然可以使用条件编译来始终禁用调试输出。
template <bool Debug>
void TestDebug(){
for(int i=0;i<1000000;i++){
// do something
if (Debug) print();
}
}
void Test(){
#ifdef DEBUG
if(m_debug) TestDebug<true>();
else TestDebug<false>();
#else
TestDebug<false>();
#endif
}
下面是一个使用调试变量的例子
class A{
public:
A(bool debug):m_debug(debug){};
~A(){};
void Test(){
for(int i=0;i<1000000;i++){
// do something
if(m_debug) print();
}
}
void print(){
std::cout << "something" << std::endl;
}
private:
bool m_debug;
};
下面是使用调试宏预处理器的示例
#include "Preprocessor.h"
class A{
public:
void Test(){
for(int i=0;i<1000000;i++){
// do something
#ifdef DEBUG
print();
#endif
}
}
void print(){
std::cout << "something" << std::endl;
}
};
在Preprocessor.h中就是
#define DEBUG
使用调试变量的好处是 class 减少了对全局预处理器头文件的依赖。宏方法的好处是在 运行 时间执行的 if 语句少了 1000000 条,这对于假设每个 fps 都很重要的图形应用程序来说可能是至关重要的。什么会被认为是更好的方法?
更好的方法是使用预处理器,但是,它不需要新的头文件来定义宏。
您可以在编译时设置标志,使用 -DMACRO_NAME
或者,在您的情况下,-DDEBUG
。
首先,宏方法在内存和测试方面都更好(尽管这确实是很小的成本)。你有什么特殊场景需要使用debug变量吗?
为什么不在 CPP 文件中定义 A::Test()?因此全局预处理器 header 可以移动到 CPP 文件中。无论如何,我不认为在 header 中公开此类调试细节是个好主意。
另一种选择,如果您不喜欢一堆#ifdef DEBUG / #endif 行,您可以创建一个宏来输出它的参数(如果已定义)(很像 assert 宏)。
#ifdef DEBUG
#define PRINT(x) (x)
#else
#define PRINT(x)
#endif
PRINT( std::cout << "something" << std::endl );
只要作业正在打印调试信息,先例就是使用像 Visual Studio 那样的宏(debug/release 构建)。但是在 Qt 世界中,有 class QLoggingCatagory
可以在其中 enable/disable 记录部分。每次注销消息时,它都会调用函数 QLoggingCategory::isDebugEnabled()
,这让我认为至少对于正常使用来说,这不是性能的主要问题。
也就是说,如果我们将 Visual Studio MFC 应用程序与 Qt 应用程序进行比较,MFC 应用程序速度很快。这至少可以部分归因于它使用宏,并且在调试和发布版本中可以很容易地注意到差异,其中 macro/debug 信息是主要差异。
鉴于所有这些证据,我投票支持在您的情况下使用宏方法以获得最佳性能。
代码路径并不比 "compiled away" 更小。但是,如果您愿意执行重构步骤,则可以以更大的可执行文件为代价使 run-time 调试版本更便宜。
想法是使调试状态成为 Test()
重构版本的模板参数,以便它可能会或可能不会在每次迭代时打印调试语句。如果 false
被传递给模板,编译器的死代码消除过程将优化语句,因为模板参数将被视为模板扩展中的编译时间常量。
当然,完全优化的版本仍然可以使用条件编译来始终禁用调试输出。
template <bool Debug>
void TestDebug(){
for(int i=0;i<1000000;i++){
// do something
if (Debug) print();
}
}
void Test(){
#ifdef DEBUG
if(m_debug) TestDebug<true>();
else TestDebug<false>();
#else
TestDebug<false>();
#endif
}