似乎对于printf
样式的调试,人们总是使用预处理器宏。与此类似的解决方案有什么问题吗?
void debug(char *msg) {
#ifdef DEBUG
printf("%s", msg);
#endif
}
答案 0 :(得分:10)
通常这样他们可以这样做:
#define DEBUG(MSG) printf("[%s:%i] %s\n", __FILE__, __LINE__, (MSG))
由于在日志中拥有调试消息的确切来源非常有用,因此这是一种非常常见的模式。但如果你使用了一个函数,就像这样:
void DEBUG(const char *MSG) {
printf("[%s:%i] %s\n", __FILE__, __LINE__, (MSG));
}
然后,您只能看到与printf()
中的DEBUG()
来电相对应的文件名和行号,而不是那些调用DEBUG()
的代码。
答案 1 :(得分:3)
1)如果msg
为%d
等,您的代码将会中断,因为printf需要格式字符串。 printf("%s", msg);
更好。
2)不是真的。除非您进行微优化(例如代码大小),否则会过度使用宏。函数更易于调试,因为您可以在调试器中执行stop in debug
之类的操作。有很多其他东西对于宏来说很棘手。见http://www.brainbell.com/tutors/c/Advice_and_Warnings_for_C/Macros_and_Miscellaneous_Pitfalls.html
3)正如@Jonathan Grynspan指出的那样 - 宏形式更容易用于 FILE , LINE 。在我看来,开发人员喜欢在键入时使用快捷方式,这使得他们的代码在以后更难以维护,并且后来更难以自我调试。最佳实践IMO:输入extra,使代码易于调试并易于在调试器中运行,并使用带签名的函数debug(const char* msg, const char* FILE_LOC, unsigned LINE_NUMBER)
答案 2 :(得分:3)
如果使用DEBUG
宏,则更改单个#define语句或编译选项并重新编译可能会使所有调试代码从可执行文件中消失。相比之下,如果使用DEBUG()
函数,则每次调用都会生成调用函数的代码,无论函数本身是否执行任何操作。
答案 3 :(得分:1)
除了使用__FILE__
,__LINE__
之外,您还应该比较以下内容:
#ifdef NDEBUG
#define DEBUG_PRINT(...) ((void)0)
#else
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#endif
违反你的职能:
void debug(const char* msg) {
#ifndef NDEBUG
printf("%s", msg);
#endif
}
使用宏,我可以写:
DEBUG_PRINT("Expected %d, got %d\n", correct_value, result);
使用该函数,我必须努力使用我的整数构造一个或多个字符串,并调用该函数一次或多次。在发布模式下,该函数不执行任何操作,因此字符串未使用。优化器可能设法消除构造它的代码,或者它可能不会。毫无疑问,毫无疑问。
也就是说,您可以编写debug
函数来使用varargs做正确的事情。但是你写的函数最终会遇到这个问题,你必须添加debugf
。