It seems that for printf
-style debugging people always use preprocessor macros. Is there anything wrong with a solution similar to this one?
似乎对于printf样式的调试,人们总是使用预处理器宏。和这个类似的解决方案有什么问题吗?
void debug(char *msg) {
#ifdef DEBUG
printf("%s", msg);
#endif
}
4 个解决方案
#1
10
Usually so that they can do something like this:
通常他们可以这样做:
#define DEBUG(MSG) printf("[%s:%i] %s\n", __FILE__, __LINE__, (MSG))
Since it's so useful to have the exact source of a debug message right there in the log, this is a pretty common pattern. But if you used a function, like so:
由于将调试消息的确切来源放在日志中非常有用,所以这是一个非常常见的模式。但是如果你使用一个函数,比如:
void DEBUG(const char *MSG) {
printf("[%s:%i] %s\n", __FILE__, __LINE__, (MSG));
}
Then you'd only ever get to see the filename and line number corresponding to the printf()
call in DEBUG()
, and never those of the code that called DEBUG()
.
然后,您只会看到与DEBUG()中printf()调用对应的文件名和行号,而不会看到调用DEBUG()的代码。
#2
3
1) Your code will break if msg
is %d
or such, because printf expects a format string. printf("%s", msg);
is better.
1)如果msg为%d或其他类型,您的代码将会中断,因为printf需要一个格式字符串。printf(" % s ",味精);是更好的。
2) Not really. Macros are overused unless you're micro-optimizing (e.g. for code size). Functions are easier to debug with since you can do stuff like stop in debug
in your debugger. There's a zillion other things that are tricky with macros. See http://www.brainbell.com/tutors/c/Advice_and_Warnings_for_C/Macros_and_Miscellaneous_Pitfalls.html
2)没有。宏被过度使用,除非您正在进行微优化(例如,对于代码大小)。函数更易于调试,因为您可以在调试器中执行诸如“在调试中停止”之类的操作。有无数其他的事情是复杂的宏。参见http://www.brainbell.com/tutors/c/Advice_and_Warnings_for_C/Macros_and_Miscellaneous_Pitfalls.html
3) As @Jonathan Grynspan pointed out - the macro form is easier to use with FILE , LINE . In my opinion developers like taking shortcuts in typing that make their code harder to maintain for others later, and ironically harder to debug themselves later. Best practice IMO: type extra, make your code easy to debug and easy to run in a debugger, and use a function with signature debug(const char* msg, const char* FILE_LOC, unsigned LINE_NUMBER)
3)如@Jonathan Grynspan所指出的,宏表单更容易与FILE, LINE一起使用。在我看来,开发人员喜欢在键入过程中使用快捷键,这使得他们的代码在以后更难维护,而且具有讽刺意味的是,在以后更难调试自己。最佳实践IMO:输入额外的字符,使代码易于调试并易于在调试器中运行,并使用带有签名调试的函数(const char* msg, const char* FILE_LOC, unsigned LINE_NUMBER)
#3
3
If one uses a DEBUG
macro, then changing a single #define statement or compilation option and recompiling can make all of the debug code vanish from the executable. By contrast, if one uses a DEBUG()
function, then every invocation will generate code to call the function, whether or not the function itself does anything.
如果使用调试宏,那么更改单个#define语句或编译选项并重新编译可以使所有的调试代码从可执行文件中消失。相反,如果使用DEBUG()函数,那么每次调用都会生成调用函数的代码,无论函数本身是否做任何事情。
#4
1
As well as the use of __FILE__
, __LINE__
, you should also compare the following:
除了使用__FILE__、__LINE__之外,您还应该比较以下内容:
#ifdef NDEBUG
#define DEBUG_PRINT(...) ((void)0)
#else
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#endif
Against your function:
对你的函数:
void debug(const char* msg) {
#ifndef NDEBUG
printf("%s", msg);
#endif
}
With the macro, I can write:
使用宏,我可以写:
DEBUG_PRINT("Expected %d, got %d\n", correct_value, result);
With the function, I have to go to some effort to construct one or more strings using my integers, and call the function one or more times. In release mode the function does nothing, so the string is unused. The optimizer might manage to eliminate the code to construct it, or then again it might not. With the macro there's no doubt.
对于这个函数,我必须努力使用我的整数构造一个或多个字符串,并调用一个或多个函数。在释放模式下,函数什么都不做,因此字符串未被使用。优化器可能会设法消除构建它的代码,也可能不会。在宏观方面,毫无疑问。
That said, you could write your debug
function to do the right thing with varargs. But your function as written will hit this problem eventually, and you'll have to add a debugf
.
也就是说,您可以编写调试函数来用varargs做正确的事情。但是你写的函数最终会遇到这个问题,你需要添加一个debugf。
#1
10
Usually so that they can do something like this:
通常他们可以这样做:
#define DEBUG(MSG) printf("[%s:%i] %s\n", __FILE__, __LINE__, (MSG))
Since it's so useful to have the exact source of a debug message right there in the log, this is a pretty common pattern. But if you used a function, like so:
由于将调试消息的确切来源放在日志中非常有用,所以这是一个非常常见的模式。但是如果你使用一个函数,比如:
void DEBUG(const char *MSG) {
printf("[%s:%i] %s\n", __FILE__, __LINE__, (MSG));
}
Then you'd only ever get to see the filename and line number corresponding to the printf()
call in DEBUG()
, and never those of the code that called DEBUG()
.
然后,您只会看到与DEBUG()中printf()调用对应的文件名和行号,而不会看到调用DEBUG()的代码。
#2
3
1) Your code will break if msg
is %d
or such, because printf expects a format string. printf("%s", msg);
is better.
1)如果msg为%d或其他类型,您的代码将会中断,因为printf需要一个格式字符串。printf(" % s ",味精);是更好的。
2) Not really. Macros are overused unless you're micro-optimizing (e.g. for code size). Functions are easier to debug with since you can do stuff like stop in debug
in your debugger. There's a zillion other things that are tricky with macros. See http://www.brainbell.com/tutors/c/Advice_and_Warnings_for_C/Macros_and_Miscellaneous_Pitfalls.html
2)没有。宏被过度使用,除非您正在进行微优化(例如,对于代码大小)。函数更易于调试,因为您可以在调试器中执行诸如“在调试中停止”之类的操作。有无数其他的事情是复杂的宏。参见http://www.brainbell.com/tutors/c/Advice_and_Warnings_for_C/Macros_and_Miscellaneous_Pitfalls.html
3) As @Jonathan Grynspan pointed out - the macro form is easier to use with FILE , LINE . In my opinion developers like taking shortcuts in typing that make their code harder to maintain for others later, and ironically harder to debug themselves later. Best practice IMO: type extra, make your code easy to debug and easy to run in a debugger, and use a function with signature debug(const char* msg, const char* FILE_LOC, unsigned LINE_NUMBER)
3)如@Jonathan Grynspan所指出的,宏表单更容易与FILE, LINE一起使用。在我看来,开发人员喜欢在键入过程中使用快捷键,这使得他们的代码在以后更难维护,而且具有讽刺意味的是,在以后更难调试自己。最佳实践IMO:输入额外的字符,使代码易于调试并易于在调试器中运行,并使用带有签名调试的函数(const char* msg, const char* FILE_LOC, unsigned LINE_NUMBER)
#3
3
If one uses a DEBUG
macro, then changing a single #define statement or compilation option and recompiling can make all of the debug code vanish from the executable. By contrast, if one uses a DEBUG()
function, then every invocation will generate code to call the function, whether or not the function itself does anything.
如果使用调试宏,那么更改单个#define语句或编译选项并重新编译可以使所有的调试代码从可执行文件中消失。相反,如果使用DEBUG()函数,那么每次调用都会生成调用函数的代码,无论函数本身是否做任何事情。
#4
1
As well as the use of __FILE__
, __LINE__
, you should also compare the following:
除了使用__FILE__、__LINE__之外,您还应该比较以下内容:
#ifdef NDEBUG
#define DEBUG_PRINT(...) ((void)0)
#else
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#endif
Against your function:
对你的函数:
void debug(const char* msg) {
#ifndef NDEBUG
printf("%s", msg);
#endif
}
With the macro, I can write:
使用宏,我可以写:
DEBUG_PRINT("Expected %d, got %d\n", correct_value, result);
With the function, I have to go to some effort to construct one or more strings using my integers, and call the function one or more times. In release mode the function does nothing, so the string is unused. The optimizer might manage to eliminate the code to construct it, or then again it might not. With the macro there's no doubt.
对于这个函数,我必须努力使用我的整数构造一个或多个字符串,并调用一个或多个函数。在释放模式下,函数什么都不做,因此字符串未被使用。优化器可能会设法消除构建它的代码,也可能不会。在宏观方面,毫无疑问。
That said, you could write your debug
function to do the right thing with varargs. But your function as written will hit this problem eventually, and you'll have to add a debugf
.
也就是说,您可以编写调试函数来用varargs做正确的事情。但是你写的函数最终会遇到这个问题,你需要添加一个debugf。