【问题标题】:how to remove all debug printf statements from c code如何从 c 代码中删除所有调试 printf 语句
【发布时间】:2012-01-05 12:09:38
【问题描述】:

我想从我的代码中删除所有调试 printf 语句。如何通过打开/关闭调试语句而不使用条件调试来做到这一点?

我使用 printf 只是为了检查特定值是否正确...如下所示...: printf("value read %d\n", a);

【问题讨论】:

  • 调试 printf 语句和“正常” printf 语句有什么区别吗?

标签: c linux embedded


【解决方案1】:

如果不使用编辑器删除它们,您将无法做到这一点。

你可以做的是:

Allen Holub 在他的 book 中推荐 使用以下调试宏:

#ifdef DEBUG
#  define D(x) x
#else
#  define D(x) 
#endif

并像这样使用它:

D(printf("oh, hai, debug"));

【讨论】:

  • 使用条件宏进行调试打印有什么好处.....?这是减小可执行文件大小...请告诉...
  • 当DEBUG 没有定义时,D(...) 中的所有内容甚至在编译之前都会被(由预处理器)解散——即这些语句没有开销。而且,是的,这减少了可执行文件的大小。
  • hmm 最后一行不应该是 D(printf("oh, hai, debug");) 而不是 D(printf("oh, hai, debug"));? (注意分号位置)当前,如果未定义调试,则不必要的“;”会留下还是我错了?
  • @stefan.at.wpf,是的,你是对的,这将给予奖励“;”如果未定义 DEBUG。
  • @stefan.at.wpf 多余的分号无关紧要,因为那是 C 中的无操作。
【解决方案2】:

将所有printf() 调用替换为DEBUG()。 DEBUG 是一个宏定义为:

#define DEBUG printf

这将调用真正的printf() 函数,或者你也可以将其定义为:

#define DEBUG fake_printf

然后调用 fake printf 来抑制调试信息。

fake printf 函数可能很蹩脚:

int fake_printf( const char * format, ... )
{
    return 0;
}

【讨论】:

  • 我不会推荐这种方法,至少对于 GCC。编译器通常不会内联可变参数调用(但通过__builtin_printf 有一些关于printf 的内置知识),即使这样做,printf 内的所有函数调用都会被调用,你不希望这样.
  • 很有趣,谢谢。我现在正在使用 VStudio,我怀疑它在这个问题上的行为与 GCC 不同。
  • 你确定 VStudio 是内联可变参数吗?你有参考吗?即使这样做了,您传递给fake_printf 的函数调用(例如log 或您自己计算的Pi 的第N 位)也会被调用,所以这并不正确。您不希望计算参数的副作用。
  • 我明白你在说什么,我同意你的看法。我考虑过删除此答案,但由于您的信息丰富,我将把它留在这里。再次感谢
【解决方案3】:

您应该解释如何进行调试printf。一个简单的方法可能是有一个宏像

bool debug_flag; // to be set in the debugger or at initialization
pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
#define debugprintf(Fmt,...) debugprintf_at(__FILE__,__LINE__,Fmt,__VA_ARGS__)
#ifndef NDEBUG
#define debugprintf_at(Fil,Lin,Fmt,...) do {if (debug_flag) {       \
  pthread_mutex_lock(&debug_mutex);                                 \
  fprintf (stderr, "%s:%d %s:" Fmt, Fil, Lin, __func__,             \
         ##__VA_ARGS__);                                            \
  pthread_mutex_unlock(&debug_mutex); }                             \
} while(0)
#else
#define debugprintf(Fmt,...) do {} while(0)
#endif

(它使用互斥锁是因为您不想混合来自不同线程的调试 printf 消息;如果您不使用任何线程,请移除互斥锁及其锁定。)

如果您的问题是如何在一个庞大的软件(拥有其源代码)中找到所有调试 printf,您可以尝试使用 grep 或更高级的东西,如 GCC 插件或 MELT 延期。但是这种方法(GCC 定制)需要时间(一周或更长时间的工作),并且只对庞大的软件库(例如数百万行源代码)有价值。

对于不太大的软件,只需手动检查代码中的所有 printf,然后将您认为用于调试的那些替换为 debugprintf 宏调用。

【讨论】:

  • 赞成,因为您的 debugprintf() 宏在禁用调试时有效地删除了参数的评估和存储。在发布的其他解决方案中,仍然有一个空函数调用。
【解决方案4】:

在 Visual Studio 中,如果 printf 在一行上,您可以使用正则表达式查找/替换来删除 printf 语句。好的,这将非常费力,但可能会奏效。

或者,编写另一个控制台应用程序来解析您的代码并为您执行此操作(然后您可以处理多行语句)。

在调试日志方面采用的一个很好的模式是用全局函数或宏替换整个代码中的 printf 语句并调用它。例如,如果您有一个全局 Log(const char* message) 函数(或宏),如果您想更改日志记录的操作方式,则可以更改该实现一次,而不是用预处理器语句乱扔代码。

比这更进一步,有许多logging frameworks(和here)执行相同的操作,但具有更多的可配置性。

【讨论】:

  • 嵌入式应用程序不是用 Visual Studio 编写的,主要需要干净、小巧和快速的解决方案
  • @friendzis ,我对 Visual Studio 的评论与使用宏或全局函数的代码解决方案无关,而是与提供 Regex 查找/替换的 IDE 有关。我相信notepad++也有同样的功能。
  • @friendzis 我有时使用 Visual Studio 编写 C/C++ 并使用 AVR 编译。见instructables.com/id/…
【解决方案5】:

这是我使用的一种方法:

#if !defined ( NDEBUG )
    void PrintMsg( const char_t* pFormat, ... )
    {
        va_list args;
        va_start( args, pFormat );
        (void)vprintf( pFormat, args );
        va_end( args );
    }
#else
    void PrintMsg( const char_t*, ... )
    {
    }
#endif


#define DBG_PRINTF      PrintMsg

然后将代码中的所有“printf”替换为“DBG_PRINTF”

它还将执行 printf 函数的参数。

【讨论】:

    【解决方案6】:

    不确定这是否是问题。我个人喜欢为调试信息使用单独的函数/宏,它是通过预处理器指令启用的。 如果你想从生产代码中删除调试输出......想不出任何自动化的方式

    【讨论】:

      猜你喜欢
      • 2010-09-07
      • 2014-07-23
      • 2016-04-08
      • 2015-05-03
      • 2013-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多