试图创建一个宏,可以用于在定义debug时打印调试消息,就像下面的伪代码:
#define DEBUG 1
#define debug_print(args ...) if (DEBUG) fprintf(stderr, args)
这是如何用宏来完成的呢?
试图创建一个宏,可以用于在定义debug时打印调试消息,就像下面的伪代码:
#define DEBUG 1
#define debug_print(args ...) if (DEBUG) fprintf(stderr, args)
这是如何用宏来完成的呢?
当前回答
所以,当使用gcc时,我喜欢:
#define DBGI(expr) ({int g2rE3=expr; fprintf(stderr, "%s:%d:%s(): ""%s->%i\n", __FILE__, __LINE__, __func__, #expr, g2rE3); g2rE3;})
因为它可以插入到代码中。
假设您正在尝试调试
printf("%i\n", (1*2*3*4*5*6));
720
然后你可以把它改成:
printf("%i\n", DBGI(1*2*3*4*5*6));
hello.c:86:main(): 1*2*3*4*5*6->720
720
你可以得到一个表达式被求值为什么的分析。
这样就避免了双重评估的问题,但缺少物理系统确实会导致名称冲突。
然而它是嵌套的:
DBGI(printf("%i\n", DBGI(1*2*3*4*5*6)));
hello.c:86:main(): 1*2*3*4*5*6->720
720
hello.c:86:main(): printf("%i\n", DBGI(1*2*3*4*5*6))->4
所以我认为,只要避免使用g2rE3作为变量名,就可以了。
当然,我发现它(以及字符串的联合版本,以及调试级别的版本等)非常宝贵。
其他回答
根据http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html, __VA_ARGS__之前应该有##。
否则,宏#define dbg_print(format,…)printf(format, __VA_ARGS__)将不会编译以下示例:dbg_print("hello world");
对于一个可移植的(ISO C90)实现,您可以使用双括号,就像这样;
#include <stdio.h>
#include <stdarg.h>
#ifndef NDEBUG
# define debug_print(msg) stderr_printf msg
#else
# define debug_print(msg) (void)0
#endif
void
stderr_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
int
main(int argc, char *argv[])
{
debug_print(("argv[0] is %s, argc is %d\n", argv[0], argc));
return 0;
}
或者(不推荐)
#include <stdio.h>
#define _ ,
#ifndef NDEBUG
# define debug_print(msg) fprintf(stderr, msg)
#else
# define debug_print(msg) (void)0
#endif
int
main(int argc, char *argv[])
{
debug_print("argv[0] is %s, argc is %d"_ argv[0] _ argc);
return 0;
}
下面我最喜欢的是var_dump,当它被调用时:
var_dump(“%d”, 计数);
产生如下输出:
Patch.c:150:main(): count = 0
感谢@“Jonathan Leffler”。所有都是c89快乐的:
Code
#define DEBUG 1
#include <stdarg.h>
#include <stdio.h>
void debug_vprintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
/* Call as: (DOUBLE PARENTHESES ARE MANDATORY) */
/* var_debug(("outfd = %d, somefailed = %d\n", outfd, somefailed)); */
#define var_debug(x) do { if (DEBUG) { debug_vprintf ("%s:%d:%s(): ", \
__FILE__, __LINE__, __func__); debug_vprintf x; }} while (0)
/* var_dump("%s" variable_name); */
#define var_dump(fmt, var) do { if (DEBUG) { debug_vprintf ("%s:%d:%s(): ", \
__FILE__, __LINE__, __func__); debug_vprintf ("%s = " fmt, #var, var); }} while (0)
#define DEBUG_HERE do { if (DEBUG) { debug_vprintf ("%s:%d:%s(): HERE\n", \
__FILE__, __LINE__, __func__); }} while (0)
我使用的方法是这样的:
#ifdef DEBUG
#define D if(1)
#else
#define D if(0)
#endif
而我只是用D作为前缀:
D printf("x=%0.3f\n",x);
编译器看到调试代码,没有逗号的问题,它的工作无处不在。此外,当printf不够用时,比如当你必须转储一个数组或计算一些对程序本身是冗余的诊断值时,它也可以工作。
编辑:好的,它可能会产生一个问题,当附近有其他地方可以被这个注入的if拦截。下面是一个版本:
#ifdef DEBUG
#define D
#else
#define D for(;0;)
#endif
#define debug_print(FMT, ARGS...) do { \
if (DEBUG) \
fprintf(stderr, "%s:%d " FMT "\n", __FUNCTION__, __LINE__, ## ARGS); \
} while (0)