C 宏上的空括号实现了什么?
我在C语言中遇到了一个我无法计算的宏。我感到困惑的是宏名称C 宏上的空括号实现了什么?,c,macros,c-preprocessor,C,Macros,C Preprocessor,我在C语言中遇到了一个我无法计算的宏。我感到困惑的是宏名称myTEST\u MARK()末尾的附加括号。这真的有什么作用吗?还是只是一种命名约定 #ifndef myTEST_FLAG #define myTEST_FLAG() #endif … //usage: if (condition) { do something } else { myTEST_FLAG(); } 我了解有关文本替换和设置标记/标志的基础知识,也许这里的#定义是为了帮助以后调试?宏可以有
myTEST\u MARK()
末尾的附加括号。这真的有什么作用吗?还是只是一种命名约定
#ifndef myTEST_FLAG
#define myTEST_FLAG()
#endif
…
//usage:
if (condition) {
do something
} else {
myTEST_FLAG();
}
我了解有关文本替换和设置标记/标志的基础知识,也许这里的#定义是为了帮助以后调试?宏可以有参数,因为它们实现某种内联函数。带有空括号的宏只是模拟一个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\u CONFIG\u TAG\u 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();
}
通过这种方式,您可以轻松地编译调试版本,以启用生产版本中可能要删除的所有日志。宏可以有参数,因为它们实现某种内联函数。带有空括号的宏只是模拟一个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\u CONFIG\u TAG\u 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();
}
通过这种方式,您可以轻松编译调试版本,以启用生产版本中可能要删除的所有日志。用括号定义的宏是“类似函数”的宏。不会识别和展开没有参数的宏实例 定义一个没有参数的函数类宏,而不是一个对象类宏,有多种原因 一个原因是,我们预计将来会有争论。如果我们更改宏,使其接受一个或多个参数,那么编译器诊断程序将找到在没有参数的情况下调用宏的所有位置。如果我们更改一个类似于宏的对象,使其现在接受参数,则现有调用不会被诊断;他们只是默默地停止扩张 另一个原因是宏提供了一个函数抽象,可以想象它可以被一个不带参数的实函数所取代。我们希望通过删除宏就可以做到这一点,而不必编辑所有调用来添加括号 一致性在其中起作用。如果宏是构成接口的某组相关宏的一部分,并且其中一些宏具有参数,则无参数宏应与其他宏相同
另一个原因是宏观扩张会产生副作用。宏调用,看起来像
foo代码>看起来无害。如果它更改全局变量的值或执行I/O,看起来太无害了;如果调用看起来像foo()代码>,那么它看起来应该更加可疑。如果我们把副作用塞进一个看起来像foo代码>,然后我们使用预处理器将C转换成另一种语言,这不应该在简单的替代方法允许我们避免的情况下进行。用括号定义的宏是“类似函数”的宏。不会识别和展开没有参数的宏实例
定义一个没有参数的函数类宏,而不是一个对象类宏,有多种原因
一个原因是,我们预计将来会有争论。如果我们更改宏,使其接受一个或多个参数,那么编译器诊断程序将找到在没有参数的情况下调用宏的所有位置。如果我们更改一个类似于宏的对象,使其现在接受参数,则现有调用不会被诊断;他们只是默默地停止扩张
另一个原因是宏提供了一个函数抽象,可以想象它可以被一个不带参数的实函数所取代。我们希望通过删除宏就可以做到这一点,而不必编辑所有调用来添加括号
一致性在其中起作用。如果宏是构成接口的某组相关宏的一部分,并且其中一些宏具有参数,则无参数宏应与其他宏相同
另一个原因是宏观扩张会产生副作用。宏调用,看起来像foo代码>看起来无害。如果它更改全局变量的值或执行I/O,看起来太无害了;如果调用看起来像foo()代码>,那么它看起来应该更加可疑。如果我们把副作用塞进一个看起来像foo代码>,然后我们使用预处理器将C转换成另一种语言,这不应该在简单的替代方案允许我们避免的情况下进行。在您的情况下,基本上什么都没有。也许他们只是想让它“像”宏一样工作。在你的例子中,基本上什么都没有。也许他们只是想让它像宏一样“功能”。