使用#ifdefs和#define可选择将函数调用转换为注释
有可能做这样的事情
#ifdef SOMETHING #define foo // #else #define foo MyFunction #endif
我们的想法是,如果定义了SOMETHING,那么对foo(…)的调用将成为注释(或者不会被评估或编译的内容),否则它将成为对MyFunction的调用。
我见过__noop,但我不相信我可以使用它。
编辑(S):
我不认为我真的可以在这里使用宏,因为MyFunction采用可变数量的参数。
另外,我想这样做,所以不评估参数! (所以做一些事情,比如评论MyFunction的主体并没有真正给我我需要的东西,因为参数仍将被评估)
试试这个:
#ifdef SOMETHING #define foo(x) #else #define foo(x) MyFunction(x) #endif
如果你的函数有几个参数,那么:
#ifdef SOMETHING #define foo(x,y,z) #else #define foo(x,y,z) MyFunction(x,y,z) #endif
如果你的函数有一个可变数量的参数,那么你的编译器可能支持所谓的“可变参数宏”,如下所示:
#ifdef SOMETHING #define foo(...) #else #define foo(...) MyFunction(__VA_ARGS__) #endif
我在实践中看到这种事情的原因是从发布版本中删除了日志记录function。 但是,另请参阅单独的“调试”和“发布”版本? 人们质疑你是否应该 有不同的构建。
或者,Jonathan对此答案的评论建议不要将函数调用重新定义为无效,而是执行如下操作:
#ifdef SOMETHING #define foo(...) do { if (false) MyFunction(__VA_ARGS__) } while (0) #else #define foo(...) do { if (true) MyFunction(__VA_ARGS__) } while (0) #endif
这样做的原因是函数调用总是被编译(因此它不会留下诸如对已删除变量的引用等无偿错误),但只在需要时调用:参见Kernighan&Pike 编程实践以及Goddard太空飞行中心编程标准 。
从debug.h文件(源自1990,因此不使用__VA_ARGS__
):
/* ** Usage: TRACE((level, fmt, ...)) ** "level" is the debugging level which must be operational for the output ** to appear. "fmt" is a printf format string. "..." is whatever extra ** arguments fmt requires (possibly nothing). ** The non-debug macro means that the code is validated but never called. ** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike. */ #ifdef DEBUG #define TRACE(x) db_print x #else #define TRACE(x) do { if (0) db_print x; } while (0) #endif /* DEBUG */
使用C99,不再需要双括号技巧。 除非C89兼容性存在问题,否则新代码不应使用它。
也许更简单的方法是有条件地省略函数的主体?
void MyFunction() { #ifndef SOMETHING #endif }
除非你特别不希望进行函数调用,否则这似乎是实现目标的一种干净方式。
不幸的是,当前的C ++版本不支持可变参数宏。
但是,您可以这样做:
#ifdef SOMETHING #define foo #else #define foo(args) MyFunction args #endif // you call it with double parens: foo((a, b, c));
如果您不希望调用foo,则将其定义为:
void foo() {}
任何对foo()的调用都应该是优化的方式。
这些方面的内容如何:
#ifdef NDEBUG #define DEBUG(STATEMENT) ((void)0) #else #define DEBUG(STATEMENT) (STATEMENT) #endif
您可以像这样使用它来记录调试消息:
DEBUG(puts("compile with -DNDEBUG and I'm gone"));
使用C99可变参数宏和__func__
标识符的格式化输出的非generics版本以及其他调试信息可能如下所示:
#ifdef NDEBUG #define Dprintf(FORMAT, ...) ((void)0) #define Dputs(MSG) ((void)0) #else #define Dprintf(FORMAT, ...) \ fprintf(stderr, "%s() in %s, line %i: " FORMAT "\n", \ __func__, __FILE__, __LINE__, __VA_ARGS__) #define Dputs(MSG) Dprintf("%s", MSG) #endif
以下是您使用这些宏的方法:
Dprintf("count = %i", count); Dputs("checkpoint passed");
可能,您不希望按照建议执行简单的“代码删除”,因为您的调用者将期望参数的副作用发生。 以下是一些麻烦的来电片段,应该让你思考:
// pre/post increment inside method call: MyFunction(i++); // Function call (with side effects) used as method argument: MyFunction( StoreNewUsernameIntoDatabase(username) );
如果您要通过简单地说:禁用MyFunction:
#define MyFunction(x)
然后调用者期望的副作用会消失,他们的代码会破坏,并且很难调试。 我喜欢上面的“sizeof”建议,我也喜欢通过#ifdef来禁用MyFunction()体的建议,尽管这意味着所有调用者都获得相同版本的MyFunction()。 从您的问题陈述中,我认为实际上并不是您想要的。
如果你真的需要在每个源文件的基础上通过预处理器定义禁用MyFunction(),那么我会这样做:
#ifdef SOMETHING #define MyFunction(x) NoOp_MyFunction(x) int NoOp_MyFunction(x) { } #endif
你甚至可以在MyFunction()的源代码和头文件中包含NoOp_MyFunction()的实现。 您还可以灵活地在NoOp_MyFunction()中添加额外的日志记录或调试信息。
不,C和C ++标准规定你不能#define某些东西作为评论,所以
#define foo //
不行。
#ifdef SOMETHING #define foo sizeof #else #define foo MyFunction #endif
我假设foo是printf
风格的函数? 无论如何,这不适用于零参数function,但如果是这种情况,您就已经知道该怎么做了。 如果你真的想成为肛门,你可以使用(void)sizeof
但这可能是不必要的。
我有点不愿意发布这个答案,因为它使用宏hackery可能成为问题的根源。 但是 – 如果对你想要消失的函数的调用总是在一个语句中单独使用(即,它们从不是一个更大的表达式的一部分),那么类似下面的东西可以工作(并且它处理varargs):
#ifdef SOMETHING #define foo (1) ? ((void) 0) : (void) #else #define foo MyFunction #endif
所以如果你有代码行:
foo( "this is a %s - a++ is %d\n", "test", a++);
它将在预处理步骤之后结束为:
MyFunction( "this is a %s - a++ is %d\n", "test", a++);
要么
(1) ? ((void) 0) : (void)( "this is a %s - a++ is %d\n", "test", a++);
它将伪函数的参数列表转换为由逗号运算符分隔的一组表达式,这些表达式永远不会被计算,因为条件总是返回((void) 0)
结果。
这种变体与ChriSW和Jonathan Leffler所建议的接近:
#ifdef SOMETHING #define foo if (0) MyFunction #else #define foo if (1) MyFunction #endif
这略有不同,因为它不需要编译器支持可变参数宏( __VA_ARGS__
)。
我认为这对于消除调试跟踪函数调用很有用,调试跟踪函数调用通常永远不会组合成更大的表达式,但除此之外,我认为这是一种危险的技术。
注意问题的可能性 – 特别是如果调用中的参数产生副作用(这是宏的一般问题 – 不仅仅是这个hack)。 在该示例中,仅当在构建中定义了SOMETHING
才会评估a++
,否则不会。 因此,如果调用后的代码取决于要增加的a
的值,则其中一个构建有一个bug。
如果我没记错的话,你应该能够#define你的宏为“没有”,这将导致编译器忽略该调用
#define foo() foo(); // this will be ignored
用myFunction围绕每个调用怎么样?
#ifdef SOMETHING myFunction(...); #endif
?