使用#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