C++ 使用 #ifdefs 和 #define 可选择将函数调用转换为注释
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/546997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use #ifdefs and #define to optionally turn a function call into a comment
提问by Daniel LeCheminant
Is it possible to do something like this
是否有可能做这样的事情
#ifdef SOMETHING
#define foo //
#else
#define foo MyFunction
#endif
The idea is that if SOMETHING is defined, then calls to foo(...) become comments (or something that doesn't get evaluated or compiled), otherwise it becomes a call to MyFunction.
这个想法是,如果定义了 SOMETHING,那么对 foo(...) 的调用就变成了注释(或者一些没有被评估或编译的东西),否则它就变成了对 MyFunction 的调用。
I've seen __noop used, but I don't believe I can use that.
我见过使用 __noop,但我不相信我可以使用它。
EDIT(s):
编辑:
I don't think I can really use a macro here, because MyFunction takes a variable number of arguments.
我不认为我真的可以在这里使用宏,因为 MyFunction 需要可变数量的参数。
Also, I'd like to make it so the arguments are NOT evaluated! (So doing something like commenting out the body of MyFunction doesn't really give me what I need, as the arguments will still be evaluated)
另外,我想这样做,以便不评估参数!(所以做一些像注释掉 MyFunction 的主体并没有真正给我我需要的东西,因为参数仍然会被评估)
回答by ChrisW
Try this:
尝试这个:
#ifdef SOMETHING
#define foo(x)
#else
#define foo(x) MyFunction(x)
#endif
If your function has several arguments, then:
如果您的函数有多个参数,则:
#ifdef SOMETHING
#define foo(x,y,z)
#else
#define foo(x,y,z) MyFunction(x,y,z)
#endif
If your function has a variable number of arguments, then your compiler may support so-called "variadic macros", like this:
如果您的函数具有可变数量的参数,那么您的编译器可能支持所谓的“可变参数宏”,如下所示:
#ifdef SOMETHING
#define foo(...)
#else
#define foo(...) MyFunction(__VA_ARGS__)
#endif
The reason which I've seen this kind of thing used in practice is to get rid of logging functions from a release build. However, see also Separate 'debug' and 'release' builds?in which people question whether you shouldeven havedifferent builds.
我在实践中看到这种事情的原因是为了摆脱发布版本的日志功能。但是,另请参阅单独的“调试”和“发布”版本?在人们质疑是否你应该甚至有不同的版本。
Alternatively, instead of redefining the function call as nothing, Jonathan's comment to this answer suggested doing something like the following:
或者,不是将函数调用重新定义为空,乔纳森对此答案的评论建议执行以下操作:
#ifdef SOMETHING
#define foo(...) do { if (false) MyFunction(__VA_ARGS__) } while (0)
#else
#define foo(...) do { if (true) MyFunction(__VA_ARGS__) } while (0)
#endif
The reasoning for doing this is so that the function call is always compiled (so it won't be left with gratuitous errors like references to deleted variables), but only called when needed: see Kernighan & Pike The Practice of Programmingand also the Goddard Space Flight Center programming standards.
这样做的原因是函数调用总是被编译(所以它不会留下无故的错误,比如对已删除变量的引用),但只在需要时调用:参见 Kernighan & Pike The Practice of Programming和Goddard航天飞行中心编程标准。
From a debug.h file (originating from 1990, and therefore not using __VA_ARGS__
):
来自 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 */
With C99, there's no longer a need for the double parentheses trick. New code should not use it unless C89 compatibility is an issue.
使用 C99,不再需要双括号技巧。除非 C89 兼容性有问题,否则新代码不应使用它。
回答by MattK
Maybe an easier way to do this would be to conditionally omit the body of the function?
也许更简单的方法是有条件地省略函数体?
void MyFunction() {
#ifndef SOMETHING
<body of function>
#endif
}
Unless you specifically don't want a function call to be made at all, this seems like a clean way to achieve your goal.
除非您特别不想进行函数调用,否则这似乎是实现目标的一种干净方式。
回答by MattK
Unfortunately the current C++ version doesn't support variadic macros.
不幸的是,当前的 C++ 版本不支持可变参数宏。
However, you can do this:
但是,您可以这样做:
#ifdef SOMETHING
#define foo
#else
#define foo(args) MyFunction args
#endif
// you call it with double parens:
foo((a, b, c));
回答by Ferruccio
If, in the case you don't want foo called, you define it as:
如果您不想调用 foo,则将其定义为:
void foo() {}
any calls to foo() should be optimized way.
对 foo() 的任何调用都应该以优化方式进行。
回答by Christoph
What about something along these lines:
沿着这些路线的东西怎么样:
#ifdef NDEBUG
#define DEBUG(STATEMENT) ((void)0)
#else
#define DEBUG(STATEMENT) (STATEMENT)
#endif
You would use it like this to log debugging messages:
您可以像这样使用它来记录调试消息:
DEBUG(puts("compile with -DNDEBUG and I'm gone"));
A non-generic version for formatted output with additional debugging information using C99 variadic macros and the __func__
identifier could look like this:
带有使用 C99 可变参数宏和__func__
标识符的附加调试信息的格式化输出的非通用版本可能如下所示:
#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
Here's how you'd use these macros:
以下是您如何使用这些宏:
Dprintf("count = %i", count);
Dputs("checkpoint passed");
回答by slacy
Likely, you don't want to do the simple "code removal" as suggested, because your callers will be expecting the side effects of the arguments to happen. Here are some troublesome caller snippets that should get you thinking:
很可能,您不想按照建议进行简单的“代码删除”,因为您的调用者会期待参数的副作用发生。这里有一些麻烦的调用者片段,应该让你思考:
// pre/post increment inside method call:
MyFunction(i++);
// Function call (with side effects) used as method argument:
MyFunction( StoreNewUsernameIntoDatabase(username) );
If you were to disable MyFunction by simply saying:
如果您要禁用 MyFunction,只需说:
#define MyFunction(x)
then the side effects that the callers were expecting would go away, and their code would break, and be quite difficult to debug. I like the "sizeof" suggestion above, and I also like the suggestion to just disable the body of MyFunction() via #ifdef's, although that means that all callers get the same version of MyFunction(). From your problem statement, I presume that's not actually what you want.
那么调用者所期望的副作用就会消失,他们的代码会崩溃,并且很难调试。我喜欢上面的“sizeof”建议,我也喜欢通过#ifdef 禁用 MyFunction() 主体的建议,尽管这意味着所有调用者都获得相同版本的 MyFunction()。根据您的问题陈述,我认为这实际上不是您想要的。
If you really need to disable MyFunction() via preprocessor defines on a per-source-file basis, then I'd do it like this:
如果您确实需要通过基于每个源文件的预处理器定义禁用 MyFunction(),那么我会这样做:
#ifdef SOMETHING
#define MyFunction(x) NoOp_MyFunction(x)
int NoOp_MyFunction(x) { }
#endif
You could even include the implementation of NoOp_MyFunction() inside the source & headers for MyFunction(). You also have the flexibility to add extra logging or debugging information in NoOp_MyFunction() as well.
您甚至可以在 MyFunction() 的源代码和标头中包含 NoOp_MyFunction() 的实现。您还可以灵活地在 NoOp_MyFunction() 中添加额外的日志记录或调试信息。
回答by Michael Burr
I'm a little reluctant to post this answer because it's use of macro hackery can become the source of problems. However - ifthe calls to the function you want to have disappear are always used alone in a statement (ie., they are never part of a larger expression), then something like the following could work (and it handles varargs):
我有点不愿意发布这个答案,因为它对宏黑客的使用可能成为问题的根源。但是 -如果对您想要消失的函数的调用总是在语句中单独使用(即,它们永远不会成为更大表达式的一部分),那么类似以下内容可以工作(并且它处理可变参数):
#ifdef SOMETHING
#define foo (1) ? ((void) 0) : (void)
#else
#define foo MyFunction
#endif
So if you have the line of code:
因此,如果您有以下代码行:
foo( "this is a %s - a++ is %d\n", "test", a++);
it will end up after the preprocessing step as either:
它将在预处理步骤之后结束为:
MyFunction( "this is a %s - a++ is %d\n", "test", a++);
or
或者
(1) ? ((void) 0) : (void)( "this is a %s - a++ is %d\n", "test", a++);
which turns the pseudo-function's parameter list into a bunch of expressions separated by the comma operator that will never be evaluated, since the conditional always returns the ((void) 0)
result.
它将伪函数的参数列表转换成一堆由逗号运算符分隔的表达式,这些表达式永远不会被计算,因为条件总是返回((void) 0)
结果。
A variant of this is something close to what ChriSW and Jonathan Leffler suggested:
其变体与 ChriSW 和 Jonathan Leffler 的建议相近:
#ifdef SOMETHING
#define foo if (0) MyFunction
#else
#define foo if (1) MyFunction
#endif
This is slightly different in that it does not require the compiler to support variadic macros (__VA_ARGS__
).
这略有不同,因为它不需要编译器支持可变参数宏 ( __VA_ARGS__
)。
I think this can be useful for eliminating debug trace function calls which are generally never combined into a larger expression, but beyond that I think it's a dangerous technique.
我认为这对于消除通常永远不会组合成更大表达式的调试跟踪函数调用很有用,但除此之外,我认为这是一种危险的技术。
Note the potential for problems - especially if the parameters in the call produce side-effects (this is a general problem with macros - not just this hack). In the example, the a++
will be evaluated only if SOMETHING
is defined in the build, otherwise it's not. So if code after the call depends on the value of a
to be incremented, one of the builds has a bug.
注意潜在的问题 - 特别是如果调用中的参数产生副作用(这是宏的普遍问题 - 不仅仅是这个 hack)。在示例中,a++
仅当SOMETHING
在构建中定义时才会评估,否则不会。因此,如果调用后的代码取决于a
要递增的值,则其中一个构建存在错误。
回答by Michael Burr
No, the C and C++ Standards say you cannot #define something to be a comment, so
不,C 和 C++ 标准说你不能#define 成为注释,所以
#define foo //
won't work.
不会工作。
回答by MSN
#ifdef SOMETHING
#define foo sizeof
#else
#define foo MyFunction
#endif
I'm assuming that foo is a printf
style function? Anyways, this won't work with a zero parameter function, but if that were the case, you would already know what to do. If you really want to be anal you can use (void)sizeof
but that's probably unnecessary.
我假设 foo 是一个printf
样式函数?无论如何,这不适用于零参数函数,但如果是这种情况,您就会知道该怎么做。如果你真的想成为肛门,你可以使用,(void)sizeof
但这可能是不必要的。
回答by Brian Postow
What about surrounding each call to myFunction with
围绕每个对 myFunction 的调用怎么样
#ifdef SOMETHING
myFunction(...);
#endif
?
?