柔性数组
2026/7/12大约 2 分钟
柔性数组
柔性数组(Flexible Array Member)*是 C99 引入的一种特殊数组成员:它必须是结构体的*最后一个成员,声明时不指定数组大小。
typedef struct {
uint16_t len;
uint8_t data[];
} Packet;这里:
data[]没有分配固定长度,它只是告诉编译器:
结构体后面还可以紧跟一段连续的数组空间。
一、最简单的例子
假设我们要保存:
长度:5
数据:hello可以这样分配:
uint16_t data_len = 5;
Packet *p = malloc(sizeof(Packet) + data_len);
p->len = data_len;
memcpy(p->data, "hello", data_len);可以理解成内存:
malloc(sizeof(Packet) + 5)
┌──────────────┬─────────────────┐
│ len │ data[5] │
├──────────────┼─────────────────┤
│ 2 字节 │ h e l l o │
└──────────────┴─────────────────┘所以 data 实际就在 Packet 后面。
二、为什么 sizeof(Packet) 不包含 data?
printf("%zu\n", sizeof(Packet));这里只计算固定部分:
len
↓
2 字节data[] 没有固定大小,所以不会算进去。
因此:
malloc(sizeof(Packet) + data_len);就是:
固定的 Packet
+
实际需要的数据空间三、完整代码
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
uint16_t len;
uint8_t data[];
} Packet;
int main(void)
{
const char msg[] = "hello";
uint16_t len = strlen(msg);
Packet *p = malloc(sizeof(Packet) + len);
if (p == NULL)
return -1;
p->len = len;
memcpy(p->data, msg, len);
printf("len = %d\n", p->len);
printf("data = %.*s\n", p->len, p->data);
free(p);
return 0;
}输出:
len = 5
data = hello四、和普通指针方案对比
普通写法:
typedef struct {
uint16_t len;
uint8_t *data;
} Packet;需要两次分配:
Packet *p = malloc(sizeof(Packet));
p->data = malloc(data_len);内存关系:
p
↓
┌─────────┐
│ len │
│ data ───┼────────→ ┌────────────┐
└─────────┘ │ 实际数据 │
└────────────┘柔性数组:
typedef struct {
uint16_t len;
uint8_t data[];
} Packet;只需要一次:
Packet *p = malloc(sizeof(Packet) + data_len);内存连续:
┌─────────┬────────────┐
│ len │ data │
└─────────┴────────────┘所以柔性数组的优势是:
一次分配、内存连续、不需要额外保存一个数据指针。
五、嵌入式中最常见的用途
例如一个变长数据包:
typedef struct {
uint16_t type;
uint16_t len;
uint8_t data[];
} Packet;收到长度为 20 的数据:
Packet *p = malloc(sizeof(Packet) + 20);内存就是:
┌────────┬────────┬────────────────────┐
│ type │ len │ data[20] │
└────────┴────────┴────────────────────┘因此柔性数组特别适合:
变长协议报文、网络数据包、消息缓冲区。
最终记忆
typedef struct {
uint16_t len;
uint8_t data[];
} Packet;核心就是:
sizeof(Packet)
↓
只算固定部分
malloc(sizeof(Packet) + N)
↓
结构体 + N 字节数据空间柔性数组 = 结构体固定部分 + 紧跟在后面的可变长度数据。

