_Generic能否匹配类型名称字符串?
解决方案
针对你提到的「根据类型名称分支处理构造逻辑」的需求,宏字符串化确实是可行的思路,但要结合C语言的预处理特性或C11的类型泛型来实现,以下是几种实用方案:
1. 已知类型变体:用C11类型泛型(最可靠)
如果Point的变体(如Point__alloca、Point__boehm)是提前确定的,用_Generic实现静态类型分支比字符串化更直接,编译期就能完成类型匹配,性能更高:
// 先实现各类型的构造函数 Point__alloca* create_Point__alloca() { return (Point__alloca*)alloca(sizeof(Point__alloca)); } Point__boehm* create_Point__boehm() { return (Point__boehm*)boehm_alloc(sizeof(Point__boehm)); } // 核心new宏,自动匹配类型对应的构造逻辑 #define new(T) _Generic((T){0}, \ Point__alloca*: create_Point__alloca(), \ Point__boehm*: create_Point__boehm(), \ default: NULL /* 未知类型的默认处理 */ \ ) // 使用示例 Point__alloca* p1 = new(Point__alloca); Point__boehm* p2 = new(Point__boehm);
2. 匹配含"int"的类型:预处理字符串化+静态检测
如果需要对所有名称包含"int"的类型统一处理,可以结合字符串化宏和预处理技巧实现静态判断(注:C预处理无原生字符串包含检测,需借助宏拼接技巧):
基础字符串化宏
#define STRINGIFY(x) #x #define TYPE_NAME(T) STRINGIFY(T)
预处理阶段检测类型名是否含"int"
// 辅助宏:通过拼接判断字符串是否包含"int" #define CHECK_INT_IN_NAME(str) str##_int_marker_ #define HAS_INT(T) \ (sizeof(CHECK_INT_IN_NAME(TYPE_NAME(T))) != sizeof(""_int_marker_))
原理:如果类型名称包含"int",拼接后的字符串长度会比""_int_marker_长,反之则相等。
分支处理的new宏
// 含"int"类型的通用构造逻辑 #define create_int_type(T) ((T*)malloc(sizeof(T))) // 其他类型的构造示例 #define create_default_type(T) ((T*)calloc(1, sizeof(T))) #define new(T) \ _Generic((T){0}, \ default: HAS_INT(T) ? create_int_type(T) : create_default_type(T) \ )
这种方式的局限性:仅能处理"int"连续出现的场景,且依赖编译器支持预处理阶段的字符串常量sizeof判断。
3. 运行时动态匹配:字符串化+字符串比较
如果需要更灵活的动态分支(比如支持新增类型无需修改宏),可以结合字符串化和strstr/strcmp实现运行时判断:
#include <string.h> #define new(T) \ ({ \ void* ptr = NULL; \ const char* type_str = TYPE_NAME(T); \ if (strstr(type_str, "int") != NULL) { \ ptr = malloc(sizeof(T)); \ } else if (!strcmp(type_str, "Point__alloca")) { \ ptr = alloca(sizeof(T)); \ } else if (!strcmp(type_str, "Point__boehm")) { \ ptr = boehm_alloc(sizeof(T)); \ } \ (T*)ptr; \ })
这种方式兼容性好,但属于运行时判断,性能略低于静态分支,且编译期无法做类型检查优化。
关键注意点
- 预处理阶段的操作都是静态的,无法处理运行时生成的类型名称。
_Generic是C11标准特性,需确保编译器支持(如GCC、Clang、MSVC 2015及以上版本)。- 字符串化宏
#x对大小写敏感,注意类型名称的拼写一致性。
内容的提问来源于stack exchange,提问作者Olle Härstedt
相关产品推荐
相关产品推荐

