使用GCC extensions,您可能会考虑使用类似的宏
bool silent;
#define silence(X) ({int _x; quiet(); _x = (X); verbose(); _x; })
#define printf(Fmt,...) \
do{if (!silent) printf(Fmt,##__VA_ARGS__);}while(0)
silence 宏只有在其参数X 是int 表达式(或使用typeof)时才有效。我还假设从未使用过printf 的结果。回想一下,“递归”宏是经过特殊预处理的,printf(在那个 printf 宏中)的内部出现是逐字保留的,没有宏扩展。
注意silence 不能是一个函数(否则,它的参数会在调用它之前进行评估)。并且您需要 GCC statement expressions 扩展来“记住”某个变量 _x 中的参数结果(您可以使用 __COUNTER__ 和预处理器连接生成该名称),将其作为 silence 宏的值返回调用。
然后你需要定义你的函数quiet()和verbose(),也许是这样的
void quiet()
{
silent = true;
}
void verbose()
{
silent = false,
}
如果您不想将printf 定义为您的宏,您可以在stdout 上使用freopen(3)(可能与"/dev/null" 等...)或使用dup2(2) 技巧(如suggested by Pascal Cuoq )。
如果您的代码库很大,并且您想要一些更严肃的事情并且愿意花费数天或数周的工作,请考虑使用插件或 MELT 扩展名定制您的 GCC 编译器(或请人这样做)。请注意,printf 是 GCC 已知的。
实际上,您应该定义自己的宏
#define myprintf(Fmt, ...) do{if (!silent) \
printf(Fmt,__VA_ARGS__);}while(0)
并且在任何地方都使用myprintf 而不是printf,这是一个可移植的技巧。当然,我假设您没有将printf 作为函数指针传递。
为了调试,其实我推荐
#define dbgprintf(Fmt,...) do{if (wantdebug) \
printf("%s:%d:" Fmt "\n", __FILE__, __LINE__, \
##__VA_ARGS__);}while(0)
然后我在我的代码中使用dbgprintf("i=%d",i) 或简单地使用dbgprintf("foo here")。
我正在使用##__VA_ARGS__,这是一个 GCC 扩展,用于接受 no variable arguments 到可变参数宏。如果你想要严格的 C99,你只需要说 __VA_ARGS__ 并且每个 dbgprintf 在格式后面都需要一个参数。
您也可以重新实现自己的 printf 函数,但我不建议这样做。
(请注意,事情可能更复杂,您可以使用fputs 而不是printf ....)