宏上的空括号有什么作用?
What do empty parenthesis on a macro achieve?
我在 C 中遇到了一个我无法解决的宏。我感到困惑的一点是宏名称末尾的附加括号 myTEST_MARK()
。这实际上有什么作用还是只是一种命名约定?
#ifndef myTEST_FLAG
#define myTEST_FLAG()
#endif
…
//usage:
if (condition) {
do something
} else {
myTEST_FLAG();
}
我了解有关文本替换和设置的基础知识markers/flags,也许#defines 在这里可以帮助稍后进行调试?
宏可以有参数,因为它们实现了某种内联功能。带有空括号的宏只是模拟一个 void 函数。
但是为什么要这样定义一个空的宏呢?
通常这样做是为了进行预编译级别的设置。像
#ifdef SOME_CONFIG_TAG_ENABLED
#define myTEST_FLAG() doSomething()
#else
#ifndef myTEST_FLAG
#define myTEST_FLAG()
#endif
#endif
…
//usage:
if (condition) {
do something
} else {
myTEST_FLAG();
}
用法保持不变,但如果在某处定义了SOME_CONFIG_TAG_ENABLED
(在某些config.h包含文件中或通过-D编译器选项)执行anc实际操作,否则为发表评论 没有改变来电者。
请注意,在启用部分您不仅可以拥有另一个宏,而且还可以拥有在某些情况下可能想要完全禁用的功能。一个常见的例子可能是:
// In .c:
#ifdef STATUS_DEBUG_ENABLED
void TraceStatus(void)
{
// a lot of printfs tracing the "status"
}
#endif
...
// In .h:
#ifdef STATUS_DEBUG_ENABLED
void TraceStatus(void);
#else
#define TraceStatus()
#endif
...
// Usage:
if (condition) {
do something
} else {
TraceStatus();
}
通过这种方式,您可以轻松编译一个调试版本,启用您可能希望在生产版本中删除的所有日志。
用括号定义的宏是"function-like"宏。没有参数的宏的出现将不会被识别和扩展。
定义不带参数的类函数宏而不是类对象宏有多种原因。
一个原因是我们预计将来会有争论。如果我们更改宏,使其接受一个或多个参数,那么编译器诊断将找到所有调用宏的地方,而没有参数。如果我们更改一个类似对象的宏,使其现在接受参数,则不会诊断现有调用;他们只是默默地停止扩张。
另一个原因是宏提供了一个函数抽象,并且可以被一个不带参数的真实函数所取代。我们希望能够通过删除宏来做到这一点,而不必编辑所有调用来添加括号。
一致性发挥了作用。如果宏是构成接口的一组相关宏的一部分,并且其中一些有参数,则无参数的宏应该与其他宏类似。
另一个原因是宏扩展做了一些有副作用的事情。看起来像 foo;
的宏调用看起来无害。如果它改变了一个全局变量的值或执行I/O,它看起来太无害了;如果电话看起来像 foo();
,那么它理所当然地看起来更可疑。如果我们将副作用塞进一个看起来像 foo;
的表达式中,那么我们就是在使用预处理器将 C 语言转换成另一种语言,当简单的替代方案允许我们避免它时,不应该这样做。
我在 C 中遇到了一个我无法解决的宏。我感到困惑的一点是宏名称末尾的附加括号 myTEST_MARK()
。这实际上有什么作用还是只是一种命名约定?
#ifndef myTEST_FLAG
#define myTEST_FLAG()
#endif
…
//usage:
if (condition) {
do something
} else {
myTEST_FLAG();
}
我了解有关文本替换和设置的基础知识markers/flags,也许#defines 在这里可以帮助稍后进行调试?
宏可以有参数,因为它们实现了某种内联功能。带有空括号的宏只是模拟一个 void 函数。
但是为什么要这样定义一个空的宏呢?
通常这样做是为了进行预编译级别的设置。像
#ifdef SOME_CONFIG_TAG_ENABLED
#define myTEST_FLAG() doSomething()
#else
#ifndef myTEST_FLAG
#define myTEST_FLAG()
#endif
#endif
…
//usage:
if (condition) {
do something
} else {
myTEST_FLAG();
}
用法保持不变,但如果在某处定义了SOME_CONFIG_TAG_ENABLED
(在某些config.h包含文件中或通过-D编译器选项)执行anc实际操作,否则为发表评论 没有改变来电者。
请注意,在启用部分您不仅可以拥有另一个宏,而且还可以拥有在某些情况下可能想要完全禁用的功能。一个常见的例子可能是:
// In .c:
#ifdef STATUS_DEBUG_ENABLED
void TraceStatus(void)
{
// a lot of printfs tracing the "status"
}
#endif
...
// In .h:
#ifdef STATUS_DEBUG_ENABLED
void TraceStatus(void);
#else
#define TraceStatus()
#endif
...
// Usage:
if (condition) {
do something
} else {
TraceStatus();
}
通过这种方式,您可以轻松编译一个调试版本,启用您可能希望在生产版本中删除的所有日志。
用括号定义的宏是"function-like"宏。没有参数的宏的出现将不会被识别和扩展。
定义不带参数的类函数宏而不是类对象宏有多种原因。
一个原因是我们预计将来会有争论。如果我们更改宏,使其接受一个或多个参数,那么编译器诊断将找到所有调用宏的地方,而没有参数。如果我们更改一个类似对象的宏,使其现在接受参数,则不会诊断现有调用;他们只是默默地停止扩张。
另一个原因是宏提供了一个函数抽象,并且可以被一个不带参数的真实函数所取代。我们希望能够通过删除宏来做到这一点,而不必编辑所有调用来添加括号。
一致性发挥了作用。如果宏是构成接口的一组相关宏的一部分,并且其中一些有参数,则无参数的宏应该与其他宏类似。
另一个原因是宏扩展做了一些有副作用的事情。看起来像 foo;
的宏调用看起来无害。如果它改变了一个全局变量的值或执行I/O,它看起来太无害了;如果电话看起来像 foo();
,那么它理所当然地看起来更可疑。如果我们将副作用塞进一个看起来像 foo;
的表达式中,那么我们就是在使用预处理器将 C 语言转换成另一种语言,当简单的替代方案允许我们避免它时,不应该这样做。