获取结构体属性大小的宏为何用空指针?有其他实现方式吗?
size_of_attribute宏使用空指针的原因及替代实现 背景代码
Row 结构体定义
typedef struct { uint32_t id; char username[COLUMN_USERNAME_SIZE]; char email[COLUMN_EMAIL_SIZE]; } Row;
属性大小获取宏及使用
#define size_of_attribute(Struct, Attribute) sizeof(((Struct *)0)->Attribute) // 各属性的大小 const uint32_t ID_SIZE = size_of_attribute(Row, id); const uint32_t USERNAME_SIZE = size_of_attribute(Row, username); const uint32_t EMAIL_SIZE = size_of_attribute(Row, email);
为什么使用空指针?
使用(Struct *)0这种空指针写法,核心目的是无需创建结构体实例即可获取成员的类型大小:
sizeof是编译期运算符,它只关注操作数的类型,不会执行实际的内存访问操作。((Struct *)0)->Attribute只是让编译器推导出Struct类型中Attribute成员的类型,进而计算该类型的大小,完全不会真的访问地址0的内存,不存在运行时崩溃风险。- 这种写法不需要额外声明结构体变量,避免了不必要的内存占用,同时保持宏的通用性——无论结构体多么复杂,都能直接用这个宏获取任意成员的大小。
该宏的其他实现方式
1. 复合字面量写法(C99及以上标准)
利用C99引入的复合字面量,创建一个临时的结构体初始化实例,同样在编译期被sizeof处理,不会生成运行时代码:
#define size_of_attribute(Struct, Attribute) sizeof(((Struct){0}).Attribute)
这种写法可读性更强,不需要依赖空指针的语法技巧,同样安全高效。
2. 依赖typeof扩展(GCC/Clang等编译器支持)
如果使用支持GNU扩展的编译器,可以用typeof直接获取成员类型:
#define size_of_attribute(Struct, Attribute) sizeof(typeof(((Struct *)0)->Attribute))
本质和原宏逻辑一致,但依赖编译器扩展,移植性不如标准写法。
3. 直接指定成员类型(不推荐)
最直接但最不灵活的方式:手动写出成员的类型来计算大小,比如sizeof(uint32_t)获取id的大小。但这种写法完全失去了宏的通用性,一旦结构体成员类型修改,必须手动更新所有相关代码,仅适用于简单场景。
内容的提问来源于stack exchange,提问作者hashim
相关产品推荐
相关产品推荐

