c++ 泛型和宏函数

c _Generic and macro funtion

我正在写 DEBUG_MSG 用于打印调试消息

#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)

_DEBUG_MSG_GENERIC是因为我想:

及其实现:

#define _DEBUG_MSG_GENERIC(strs) \
  _Generic( (strs), \
             int: _DEBUG_MSG_INT, \
             default: _DEBUG_MSG_STR \
          )(strs)

现在我想用宏函数和 printf 实现 _DEBUG_MSG_INT_DEBUG_MSG_STR :

#define _DEBUG_MSG_INT(val) printf("%d\n", val);
#define _DEBUG_MSG_STR(str) printf("%s\n", str);

但我得到的错误信息是:

main.c:14:30: error: ‘_DEBUG_MSG_INT’ undeclared (first use in this function); did you mean ‘DEBUG_MSG’?
   14 |                         int: _DEBUG_MSG_INT, \
      |                              ^~~~~~~~~~~~~~

如何解决?

是否_generic只支持函数(指向函数的指针)不支持宏函数?

完整代码

#include <stdio.h>

#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
#define _DEBUG_MSG_GENERIC(strs) \
            _Generic( (strs), \
                        int: _DEBUG_MSG_INT, \
                      default: _DEBUG_MSG_STR \
                    )(strs)
#define _DEBUG_MSG_INT(val) printf("%d\n", val)
#define _DEBUG_MSG_STR(str) printf("%s\n", str)

int main()
{
    DEBUG_MSG("str");
    DEBUG_MSG(5);
}

我认为您的问题是因为预处理器只处理一次源代码,所以 printf 不会被替换。

一个快速的解决方案是将 _DEBUG_MSG_INT(val)_DEBUG_MSG_STR(str) 定义为实函数,如下所示:

void _DEBUG_MSG_INT(int val) {
    printf("%d\n", val);
}
void _DEBUG_MSG_STR(char * str) {
    printf("%s\n", str);
}

编译器将优化额外的函数调用开销,其行为就像您直接调用 printf 一样。

问题是 _DEBUG_MSG_INT_DEBUG_MSG_STR 都是 function-like 宏,因此它们只有在紧跟 () 时才会扩展。

请注意,宏扩展发生在实际 C 编译之前,因此 _Generic 只不过是预处理器阶段的通用标识符。

我建议使用 _Generic 不是为了选择函数指针,而是为了在 printf() 中使用格式说明符。尝试:

#define _DEBUG_MSG_GENERIC(arg) printf( _DEBUG_MSG_FMTSPEC(arg), arg)
#define _DEBUG_MSG_FMTSPEC(arg) \
  _Generic( (arg), int: "%d\n", default: "%s\n")

_Generic 不是预处理器操作,不能用于 select 预处理器宏函数。 : 之后的代码在它的 case 中必须是一个 C 表达式(特别是 assignment-expression)。

您在这些位置的代码是 _DEBUG_MSG_INT_DEBUG_MSG_STR。这些是预处理器宏名称。

那些预处理器宏是 function-like 宏。只有当它们后面跟着 ( 时,它们才是 macro-replaced。在您的代码中,它们后面没有 (,因此不会替换它们。

这意味着重新处理后的代码看起来像 int : _DEBUG_MSG_INT,。所以编译器试图将 _DEBUG_MSG_INT 解释为一个表达式。由于 _DEBUG_MSG_INT 不是已声明的标识符,因此编译器会报告未声明的错误。

总之,您的代码 _Generic( (strs), int: _DEBUG_MSG_INT, default: _DEBUG_MSG_STR )(strs) 尝试使用 after-preprocessing _Generic selection 到 select preprocessing-time 宏(要么_DEBUG_MSG_INT_DEBUG_MSG_STR),然后将该宏视为 function-like 宏,在 _Generic 之后显示 (strs)。那根本行不通; after-preprocessing _Generic 无法 select 预处理宏名称。