在源代码中保留调试部分是一个好习惯吗? [关闭]

Posted

技术标签:

【中文标题】在源代码中保留调试部分是一个好习惯吗? [关闭]【英文标题】:Is leaving debug sections in the source code a good practise? [closed] 【发布时间】:2020-09-03 09:30:40 【问题描述】:

我正在与一位高级 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 

我没有他那么有经验,但是这些代码 sn-ps 到处都是,这确实阻碍了可读性和可理解性。在我看来,预处理器条件至少应该与其余代码一起使用。

我应该养成这种习惯吗?我不确定这是否是一个好方法,但在我看来,这会极大地膨胀代码,应该被排除在外。

【问题讨论】:

也许 #ifndef 可以移动到 trace 中。取决于trace 是什么以及它在其他地方的使用方式。 您可以通过将#ifdef 移动到trace 或在trace 不属于您的情况下编写包装器来改进。除此之外,虽然日志记录确实会影响代码的可读性,但它的用处远远超过了这种损失。 ...阻碍了可读性... 嗯,这取决于您使用的编辑器。就像在 VS Code 上一样,如果您定义了 NODEBUG,该块的透明度会低得多。这个问题显然是基于意见的。我认为,如果您与您的上级交谈并尝试了解他发表这些声明的观点,那肯定会有所帮助。 不错。九行代码,实现零思维。他们将在下一次加薪谈判中派上用场! 这里的“专业提示”是不要创建一个不可读的预处理器丛林,而是通过版本控制来处理它。做一个调试分支,单独维护调试代码。保存您的生产代码,使其看起来完全是垃圾。 【参考方案1】:

在调试部分添加代码通常不是一个坏习惯。 只要这段代码不会从根本上改变函数的行为,它就不会增加太多复杂性,并且可以为您提供有用的信息。但是,它确实会降低可读性。

很少有您真正需要仅在调试版本上运行的专用代码部分。我自己非常通常做的是创建只对调试版本执行操作的专用宏。这最终变得更加简洁和可读。例如:

// 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__);

如果您现在要添加 #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 */); 

【讨论】:

谢谢,这真的很有帮助! python代码有没有类似的方法? @Ceph python 没有允许您完全删除代码部分的预处理器,所以很遗憾没有。您可以创建一个名为NODEBUG 的全局常量,并编写一个debug_trace 函数,该函数仅在此变量为False 时记录。如果 NODEBUGTrue,则 JIT 编译器可能会优化此函数,但不能保证。 @JanSchultke python 也没有 jit 编译器【参考方案2】:

在源代码中保留调试部分是一种好习惯吗?

#ifndef NODEBUG
    trace("Function End %s", __FUNCTION__);
#endif 

对于是否应删除调试代码没有硬性规定。有时这是常识,由编写代码的人来决定。

显然,对于您的示例,删除这些调试代码以提高可读性已经足够简单了。

但是,一些/许多调试代码并非易事。需要时间来写。有时,对于开发人员来说,重新启用这些代码来跟踪和调试一些真正的问题是非常重要的。在这些情况下,保留这些调试代码以供以后使用/调试显然非常有用。

【讨论】:

但是,如果调试代码不是很简单,它可能应该被分解成一个单独的函数。就像打印树结构的函数一样。或类似的。即使没有从任何地方调用它们,它们也有权存在,但它们不会在程序员发现查看树结构有用的所有地方弄乱代码。 我已经看到了一些非常复杂的调试日志记录,但放在单独的函数中并不方便

以上是关于在源代码中保留调试部分是一个好习惯吗? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

这是使用 WebView 而不是 Textview 的好习惯吗? [关闭]

为 CQRS 实施包装 Masstransit 是一个好习惯吗? [关闭]

写 TODO 来提交消息是一个好习惯吗? [关闭]

从循环内部返回是一种好习惯[关闭]

C# 中的重载运算符实际上是一种好习惯吗? [关闭]

使用“视图”进行分组是一种好习惯吗?