c++ 泛型和宏函数
c _Generic and macro funtion
我正在写 DEBUG_MSG
用于打印调试消息
#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
_DEBUG_MSG_GENERIC
是因为我想:
- 当输入参数为
int
时显示 int
消息
- 当输入参数为
char*
时显示 char*
消息
及其实现:
#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 预处理宏名称。
我正在写 DEBUG_MSG
用于打印调试消息
#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
_DEBUG_MSG_GENERIC
是因为我想:
- 当输入参数为
int
时显示 - 当输入参数为
char*
时显示
int
消息
char*
消息
及其实现:
#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 预处理宏名称。