【问题标题】:Should I `#ifdef DEBUG` guard debugging functions in .c files?我应该在 .c 文件中使用“#ifdef DEBUG”保护调试功能吗?
【发布时间】:2021-11-20 05:17:03
【问题描述】:

现在我在 myfile.h 文件中有一个调试函数 printPassport。它是这样声明的:

#ifdef DEBUG
void printPassport(passport_t *passport);
#endif

这似乎是做事的正确方法,虽然我已经有一段时间没有使用 C,所以如果我错了,请纠正我。

我应该在 myfile.c 中的函数名周围加上保护吗?即我应该这样做

void printPassport(passport_t *passport) {
...
}

#ifdef DEBUG
void printPassport(passport_t *passport) {
...
}
#endif

在 myfile.c 中?

【问题讨论】:

  • 这一切都很好,但是你对函数的调用做了什么?通常,您需要#define printPassport(x),当DEBUG 未定义时,它将转换为空调用。
  • 我发现我喜欢我的调试函数(我经常称它们为 dump_xyz() 以获取 xyz 的一些重要值)具有如下签名:void dump_xyz(FILE *fp, const char *tag, const xyz *ptr); 以便它可以用于编写到stderrstdout或某种日志文件,并且可以通过标签来识别发生。有时我会变得懒惰并省略文件流参数,但该函数的生产版本通常具有所有三个参数。有时添加 const char *file, int line, const char *func 参数,同时传递 __FILE____LINE____func__ 可能会很有用。

标签: c debugging standards


【解决方案1】:

如果你保护函数,那么当你没有定义DEBUG时它不会被编译,这意味着代码将与系统的其余部分不同步。然后,当你确实需要调试代码时,你必须先修复它才能使用它。

在许多方面,最好让函数大部分时间都在编译,以便知道它是有效的。由于您在标头中有定义,因此只需为正常构建保留定义(和编译)的函数。您可以使用诸如#ifndef RELEASE_BUILD 之类的条件将未使用的功能从最终发布的产品中挤出。但关键是要保证函数正常编译,即使不正常使用。您还需要考虑如何保护对函数的调用。是否有一个运行时调试级别来激活调试,或者它是严格的编译时决定。如果是在编译时决定的,则需要对函数调用进行适当的保护,或者对函数进行宏化调用,编译器可以将其转换为((void)0) 或类似的东西。

如果函数是静态的——一个源文件的本地函数,则考虑将其设为static inline。这将被编译,但如果在不触发未使用的 static 函数的投诉的情况下从不调用它,则将被忽略,即使没有实际调用该函数。

【讨论】:

    【解决方案2】:

    NDEBUG 宏控制assert 宏;重用它而不是使用另一个宏可能会很有用。

    您是否希望该功能存在,取决于目标。如果你不需要它,你可以节省编译时间,并且通过将它保护在.cpp中而不是它来使程序更加一致。

    【讨论】:

      猜你喜欢
      • 2011-02-07
      • 2012-12-26
      • 2018-05-26
      • 2012-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-29
      • 1970-01-01
      相关资源
      最近更新 更多