如何获取指针指向的数据类型?求类似typeof的typeof_ptr实现方案
当然可以实现!
要在编译时提取指针(不管是一级还是多级)最终指向的类型,我们可以借助C语言的预处理器宏结合编译器的类型推导扩展来实现你要的typeof_ptr工具。下面分两种场景给出实现方案,适配不同的编译器和标准:
方案一:兼容C11及以上(利用_Generic)
这种方法更安全,依赖C11标准的_Generic特性,同时借助GCC/Clang的__builtin_types_compatible_p扩展来判断类型是否为指针:
#include <stdio.h> // 判断类型是否为指针(支持const/volatile修饰) #define IS_POINTER(T) \ __builtin_types_compatible_p(T, void*) || \ __builtin_types_compatible_p(T, const void*) || \ __builtin_types_compatible_p(T, volatile void*) || \ __builtin_types_compatible_p(T, const volatile void*) // 递归剥离指针层,直到得到非指针类型 #define typeof_ptr_recursive(T) \ _Generic((T), \ void*: void, \ const void*: const void, \ volatile void*: volatile void, \ const volatile void*: const volatile void, \ default: IS_POINTER(typeof(*(T*)0)) ? typeof_ptr_recursive(typeof(*(T*)0)) : typeof(*(T*)0) \ ) // 对外暴露的工具宏:先获取变量类型,再递归剥离指针 #define typeof_ptr(p) typeof_ptr_recursive(typeof(p)) // 测试示例 typedef struct { int x; } struct_t; int main() { struct_t *pointer1; struct_t **pointer2; struct_t ***pointer3; // 甚至三级指针也能处理 typeof_ptr(pointer1) a; // a 的类型是 struct_t typeof_ptr(pointer2) b; // b 的类型是 struct_t typeof_ptr(pointer3) c; // c 的类型是 struct_t // 验证类型有效性:直接访问结构体成员 a.x = 10; b.x = 20; c.x = 30; printf("a.x = %d, b.x = %d, c.x = %d\n", a.x, b.x, c.x); return 0; }
原理说明
typeof(p)先获取输入变量的类型(比如struct_t**);typeof_ptr_recursive通过_Generic判断当前类型是否为指针:- 如果是指针类型,就递归处理该指针指向的类型(比如
struct_t**指向的是struct_t*,继续递归); - 如果是非指针类型,就直接返回该类型;
- 如果是指针类型,就递归处理该指针指向的类型(比如
- 整个过程完全在编译期完成,不会产生任何运行时代码,也不会有指针解引用的风险。
方案二:GCC/Clang专属(简化递归版)
如果你只需要适配GCC或Clang这类支持typeof扩展的编译器,可以用更简洁的递归宏实现:
#include <stdio.h> #define IS_POINTER(T) \ __builtin_types_compatible_p(T, void*) || \ __builtin_types_compatible_p(T, const void*) || \ __builtin_types_compatible_p(T, volatile void*) || \ __builtin_types_compatible_p(T, const volatile void*) #define typeof_ptr(p) \ IS_POINTER(typeof(p)) ? typeof_ptr(*(p)) : typeof(p) // 测试示例同方案一 typedef struct { int x; } struct_t; int main() { struct_t *pointer1; struct_t **pointer2; typeof_ptr(pointer1) a; typeof_ptr(pointer2) b; a.x = 10; b.x = 20; printf("a.x = %d, b.x = %d\n", a.x, b.x); return 0; }
注意事项
- 这些方案依赖编译器扩展(
typeof、__builtin_types_compatible_p)或C11标准特性,标准C(C99及更早)没有原生支持typeof,但大部分现代编译器都提供了这些扩展; - 所有操作都在编译期完成,不会有运行时的性能开销或空指针访问风险;
- 如果你的场景只需要处理最多两级指针,也可以用更简单的宏:
#define typeof_ptr(p) typeof(**(1 ? &p : (void*)0))(注意这个只适用于≤2级指针)。
内容的提问来源于stack exchange,提问作者Pangi
相关产品推荐
相关产品推荐

