技巧:在编译时计算结构体成员的大小,**不需要创建实际的对象**
2025/7/6大约 2 分钟
不创建结构体对象,直接获取成员大小
在 C 语言中,如果已经定义了结构体,但只想获取某个成员的大小,不需要创建实际的结构体对象。
例如:
typedef struct
{
uint8_t flag;
uint16_t len;
char data[253];
} FlashRecord;可以直接:
sizeof(((FlashRecord *)0)->data)结果就是:
253第一步:(FlashRecord *)0
(FlashRecord *)0表示:
把整数
0转换成FlashRecord *类型的指针。
它只是一个类型为 FlashRecord \*、值为 0 的指针,并没有真的创建 FlashRecord 对象。
第二步:((FlashRecord *)0)->data
((FlashRecord *)0)->data通过 -> 指定我们要访问 FlashRecord 中的 data 成员。
编译器已经知道:
data -> char[253]所以能够得到这个成员的类型。
注意:这里并不是运行时真的去访问地址 0。
第三步:sizeof
sizeof(((FlashRecord *)0)->data)sizeof 对这种普通类型可以在编译阶段计算。
实际上就是:
((FlashRecord *)0)->data
↓
类型分析
↓
char[253]
↓
sizeof(char[253])
↓
253因此:
- 不创建
FlashRecord对象 - 不占用栈空间
- 不产生实际的地址 0 访问
- 通常没有运行时开销
为什么不用直接写 253?
因为硬编码容易和结构体定义脱节:
#define FLASH_DATA_SIZE 253如果以后改成:
char data[512];还得手动修改宏。
而:
sizeof(((FlashRecord *)0)->data)直接依赖结构体成员本身,结构体修改后会自动适应。
可以封装成宏
如果经常使用,可以写:
#define MEMBER_SIZE(type, member) \
sizeof(((type *)0)->member)然后:
if (len > MEMBER_SIZE(FlashRecord, data))
len = MEMBER_SIZE(FlashRecord, data);核心思想就是:
利用 C 语言的类型系统,在不创建实际对象的情况下,让编译器获取结构体成员的类型,再通过
sizeof在编译期计算其大小。
另外,offsetof(FlashRecord, data)也是类似的思想,只不过它获取的是 成员偏移量,而 sizeof(((FlashRecord *)0)->data) 获取的是成员大小。

