如何在带返回值的C宏中内联触发隐式指针转换以实现类型检查?
背景
我的库中有一些支持自定义内存分配器的函数:
void *(allocate)(struct allocator *allocator, size_t size, size_t alignment); void (deallocate)(struct allocator *allocator, void *pointer, size_t size, size_t alignment);
我希望对该接口做两处改进:
- 每次分配和释放内存时都需要手动编写
sizeof(type)和alignof(type); void *类型可能导致误用大小或对齐方式无效的类型指针。
这两个问题可以通过简单的宏解决:
#define allocate(allocator, type, count) \ (type *)(allocate)(allocator, sizeof(type) * (count), alignof(type)) #define deallocate(allocator, pointer, type, count) \ do { \ type *typed_pointer = pointer; \ (deallocate)(allocator, typed_pointer, sizeof(type) * (count), alignof(type)); \ } while (0)
这些宏会自动调用sizeof(type)和alignof(type),同时将指针转换为指定类型,若误用不同类型指针,编译器会发出警告。
问题
deallocate无返回值,因此可以用代码块结合变量实现隐式指针转换。但对于有返回值的函数(比如reallocate),无法用同样的方式在宏中对传入的指针进行类型检查。
是否存在一种方法,能在表达式中内联执行这种“类型检查”隐式转换,同时让宏拥有返回值?
补充说明:若可能,希望仅使用标准C,不依赖GNU或其他扩展。
解决方案
方案1:逗号表达式+无副作用类型检查(兼容C90及以上)
假设reallocate的函数原型为:
void *(reallocate)(struct allocator *allocator, void *pointer, size_t new_size, size_t alignment);
对应的宏可以这样写:
#define reallocate(allocator, pointer, type, new_count) \ ((void)(type *)pointer, (type *)(reallocate)(allocator, pointer, sizeof(type) * (new_count), alignof(type)))
原理:
(void)(type *)pointer是无副作用的类型转换操作:如果传入的pointer与type*类型不兼容(void*可隐式转换除外),编译器会直接发出类型不匹配的警告或错误。- 逗号表达式按顺序执行子表达式,最终返回最后一个表达式的结果——转换为
type*的内存重分配结果,满足宏需要返回值的要求。
方案2:C11 _Generic 严格类型校验(C11及以上)
如果代码基于C11标准,用_Generic能实现更严格的类型检查,直接拒绝非兼容类型的指针:
#define reallocate(allocator, pointer, type, new_count) \ _Generic((pointer), \ type*: (type *)(reallocate)(allocator, pointer, sizeof(type)*(new_count), alignof(type)), \ void*: (type *)(reallocate)(allocator, pointer, sizeof(type)*(new_count), alignof(type)), \ default: (void)0 /* 触发编译错误 */ \ )
原理:
_Generic根据pointer的实际类型匹配对应分支:只有type*或void*类型的指针能正常进入分配逻辑,其他类型会匹配到default分支,直接触发编译错误,从源头避免类型误用。
方案3:sizeof辅助类型检查(兼容C90及以上)
如果担心(void)转换在某些编译器下的行为,也可以用sizeof做类型校验,同样无副作用:
#define reallocate(allocator, pointer, type, new_count) \ (sizeof((type *)pointer), (type *)(reallocate)(allocator, pointer, sizeof(type)*(new_count), alignof(type)))
原理:
sizeof仅对表达式做类型分析,不会生成实际执行的代码,因此同样能触发编译器的类型不兼容警告,同时不影响宏的返回值。
内容的提问来源于stack exchange,提问作者DutChen18
相关产品推荐
相关产品推荐

