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(); } 我了解有关文本替换和设置标记/标志的基础知识,也许这里的#定义是为了帮助以后调试?宏可以有

我在C语言中遇到了一个我无法计算的宏。我感到困惑的是宏名称
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转换成另一种语言,这不应该在简单的替代方案允许我们避免的情况下进行。

在您的情况下,基本上什么都没有。也许他们只是想让它“像”宏一样工作。在你的例子中,基本上什么都没有。也许他们只是想让它像宏一样“功能”。