2012-05-24 33 views

回答

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()代码。

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指出 - 宏观形式更容易FILELINE使用。在我看来,开发人员喜欢在打字时使用快捷方式,这使得他们的代码难以在以后保持其他人的身份,并且后来更难调试。 IMO最佳实践:类型多,使你的代码易于调试,易于在调试器中运行,并使用函数签名debug(const char* msg, const char* FILE_LOC, unsigned LINE_NUMBER)

+0

我已修复我的代码,因为该错误与问题无关。 – Erik

+0

这些不是强大的参数,用于将简单的调用包装到另一个函数中的'printf'中。鉴于这个问题特别是关于printf式的调试,我不认为调试器的使用是相关的。 – chepner

3

如果使用宏,则更改单个#define语句或编译选项并重新编译可使所有调试代码从可执行文件中消失。相反,如果一个使用DEBUG()功能,则每次调用将生成代码来调用该函数,本身是否将功能做任何事情。

+0

会吗?我假设编译器会优化函数调用,至少如果我将调试函数保存在与实际代码相同的文件对象中。 – Erik

+1

一个好的编译器会优化掉空函数的调用。但是,编译器不能完全消除该功能;如声明的那样,它有外部作用域,所以编译器必须将它包含在目标文件中,以防其他模块的某些代码调用它。 (一个好的链接器可能会在以后消除它。)而且,如果它在多个源模块中定义,链接器将会抱怨多个定义。声明函数“static”允许编译器消除定义。 –

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功能,做正确的事与可变参数。但是你写的函数最终会遇到这个问题,你必须添加一个debugf

相关问题