You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在union中模拟柔性数组成员的实现是否属于未定义行为?

问题:联合体结合侵入式存储的C标准合规性判断

我原本希望实现一个结构体,既能持有指向外部存储的指针,也能存储侵入式数据,理想结构如下:

struct S {
  int other_member;  // not relevant to question
  // ...
  union {
    void *ptr;
    char buf[];
  };
};

但标准C不允许联合体包含柔性数组成员(标准仅将柔性数组成员列为结构体的特例,未明确禁止但也不支持其在联合体中使用)。

于是我改用以下实现:

struct S {
  int other_member;  // not relevant to question
  // ...
  union {
    void *ptr;
    char buf[ sizeof(void*) ];
  };
};

当需要使用侵入式存储时,执行以下操作:

if ( buf_size < sizeof(void*) )  // just in case
  buf_size = sizeof(void*);
struct S *s = malloc( sizeof(struct S) - sizeof(void*) + buf_size );

随后对s->buf读写类型为T的数据,其中sizeof(T) ≥ sizeof(void*)。

请问这种实现是否符合标准C要求?还是属于未定义行为?(我记得在柔性数组成员加入C标准前,声明buf[1]并malloc更大空间是常见做法)

备注:

  • 仅使用标准C,不使用扩展特性;
  • struct S是节点,存在大量节点,若采用侵入式存储则所有节点数据尺寸相同,尺寸存储在其他位置。

解答

这种实现符合标准C的要求,不属于未定义行为,核心依据和分析如下:

  1. 结构体与内存分配的合法性
    struct S是完全合法的标准C结构体:联合体中的buf是固定大小的数组(尺寸为sizeof(void*)),因此sizeof(struct S)是明确的固定值。你通过malloc分配的内存大小为sizeof(struct S) - sizeof(void*) + buf_size,本质是为结构体固定部分分配足够内存后,额外分配了buf_size - sizeof(void*)字节的空间——这和C99引入柔性数组成员前,用char buf[1]配合超大内存分配的经典兼容技巧逻辑完全一致,是标准允许的操作。

  2. 内存访问的合规性

    • 标准C允许访问malloc分配的内存块中,超出结构体固定大小的部分,只要不越界整个分配的内存块。你的代码中确保buf_size ≥ sizeof(void*),因此分配的内存块至少能容纳完整的struct S,额外空间的访问是合法的。
    • 联合体中buf的地址与ptr的地址完全重合,因此buf具备void*的对齐属性。由于sizeof(T) ≥ sizeof(void*),且void*的对齐要求通常是系统中最严格的基本类型对齐之一,buf的地址可以满足T的对齐需求,不会出现对齐违规的未定义行为。
  3. 关键注意事项

    • 必须严格保证buf_size不小于sizeof(void*),你的代码中已经做了校验,这能避免分配的内存小于结构体固定大小,防止访问越界。
    • 访问s->buf的扩展部分时,必须严格遵循预先存储的buf_size尺寸,不能超出malloc分配的内存块边界,否则会触发未定义行为。

内容的提问来源于stack exchange,提问作者Paul J. Lucas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 03:16:01