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

C语言不完整声明、复合类型与0长度数组规范及代码片段疑问

设计动机

这段内容是C标准化过程中针对实际开发的常见需求做的规则权衡,核心出发点有两个:

  • 兼容不完整类型的合并逻辑:实际开发中经常出现多次声明同一个数组/函数但信息不全的情况,比如先声明extern int arr[];(未指定数组长度),后面再定义int arr[10];,复合类型和类型兼容规则就是为了让这类声明能被正确合并,不会报类型不兼容的错误。
  • 兼顾零长数组的使用场景和原有标准原则:C标准一直有「长度为0的对象非法」的通用规则,所以不允许单独声明int arr[0];这类变量。但当时开发者已经普遍使用「结构体尾部放短长度数组+动态分配额外空间」的方式实现变长结构体,标准就单独为这个场景开了口子,允许零长数组作为结构体成员的特殊用法,不用严格遵守零长度对象的禁用规则。

代码片段理解

这是C99正式引入柔性数组成员之前,开发者通用的变长结构体实现范式:

struct segment {
    short int    count;
    char    c[N];
};

struct segment * new_segment( const int length ) {
    struct segment * result;
    // 申请的内存 = 结构体本身占用的大小 + 额外需要的数组空间大小
    result = malloc( sizeof(struct segment) + (length-N) );
    result->count = length;
    return result;
}

逻辑很简单:结构体本身的大小已经包含了长度为N的数组成员c的空间,如果你需要c能存储length个元素,只需要在结构体本身的大小基础上多申请length-N字节的内存即可,这些多出来的内存会紧跟在结构体后面,可以合法通过c的下标访问。
举个实际例子:如果N是1,那sizeof(struct segment)已经包含了c[0]的1字节空间,要是你需要存10个char,就多申请9字节,总空间刚好够存10个元素。

N的来源

N是代码里提前自行定义的宏常量,通常只有两种取值:

  • 如果你要兼容最严格的C89标准,就把N定义为1:这是C89唯一允许的最小数组长度,缺点是结构体本身会多占1字节的冗余空间,计算申请内存大小的时候也要多减1。
  • 如果你的编译器支持0长度数组扩展(大部分编译器比如GCC、Clang很早就支持),就把N定义为0:没有冗余空间,计算内存的时候直接加length就行,写起来更简单。
    后来C99正式把这个用法标准化为柔性数组成员,要求直接写char c[];,不需要再手动定义N,也不用处理N的取值问题。

内容的提问来源于stack exchange,提问作者Michael Munta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 01:06:03