我正在与一位高级 C++ 开发人员一起工作。在他的大部分代码中,他都包含调试部分。它看起来像这样:
void do_something() {
int var = 10
#ifndef NODEBUG
trace("Function Start %s", __FUNCTION__);
#endif
while (someCondition) {
var += 1
#ifndef NODEBUG
trace ("Var = %d \n", var)
#endif
}
... (Do some other stuff)
... (Do some more stuff)
#ifndef NODEBUG
trace("Function End %s", __FUNCTION__);
#endif
}
Run Code Online (Sandbox Code Playgroud)
我不像他那样有经验,但这些代码片段遍布代码,这确实阻碍了可读性和可理解性。在我看来,预处理器条件至少应该与其余代码适当地结合使用。
这种练习是我应该养成的习惯吗?我不确定这是否是一个好方法,但在我看来,这极大地膨胀了代码,应该被排除在外。
在源代码中留下调试部分是一个好习惯吗?
#ifndef NODEBUG
trace("Function End %s", __FUNCTION__);
#endif
Run Code Online (Sandbox Code Playgroud)
是否应该删除调试代码没有硬性规定。有时这是一种常识,由编写代码的人来决定。
显然,对于您的示例,删除这些调试代码以提高可读性就足够了。
但是,一些/许多调试代码并非微不足道。写作需要时间。有时,对于开发人员来说,重新启用这些代码以在问题发生时跟踪和调试一些实际问题非常重要。在这些情况下,保留这些调试代码以供以后使用/调试显然非常有用。
在调试部分中添加代码通常不是一个坏习惯。只要此代码不会从根本上改变您的函数的行为,它就不会增加太多复杂性,并且可以为您提供有用的信息。但是,它确实降低了可读性。
您真的需要一个仅在调试版本上运行的专用代码部分是非常罕见的。我非常普遍做自己,而不是为创建专业化的宏只有在调试版本执行操作。这最终变得更加简洁和可读。例如:
// defined in some utility header
#ifndef NODEBUG
#define DEBUG_TRACE(...) trace(__VA_ARGS__)
#else
#define DEBUG_TRACE(...)
#endif
void do_something() {
int var = 10
DEBUG_TRACE("Function Start %s", __FUNCTION__);
while (someCondition) {
var += 1
DEBUG_TRACE("Var = %d \n", var);
}
// ... (Do some other stuff)
// ... (Do some more stuff)
DEBUG_TRACE("Function End %s", __FUNCTION__);
}
Run Code Online (Sandbox Code Playgroud)
如果您#ifndef NODEBUG现在添加一个代码部分,您正在更改函数的行为而不是仅仅记录某些内容将变得更加明显。
这种做法不仅可以应用于日志记录,还可以应用于断言和其他仅在调试版本中编译的内容。如果您经常这样做,那么以下宏也可以提供帮助:
#ifndef NODEBUG
#define IF_DEBUG_ELSE(expr, alt) expr
#define IF_DEBUG(...) __VA_ARGS__
#else
#define IF_DEBUG_ELSE(expr, alt) alt
#define IF_DEBUG(...)
#endif
void example(int x) {
IF_DEBUG_ELSE(/* action on debug builds */, /* action on release builds */);
IF_DEBUG(/* one-liner action only on debug builds */);
}
Run Code Online (Sandbox Code Playgroud)