C 灵活阵列成员的真正好处是什么?

C 灵活阵列成员的真正好处是什么?,c,struct,flexible-array-member,C,Struct,Flexible Array Member,在阅读了一些与flexible array member相关的帖子后,我仍然不完全理解为什么我们需要这样一个功能 可能重复: (如果我没有解决上述可能重复的问题,那就怪我) 以下两种实现之间的实际差异是什么: struct h1 { size_t len; unsigned char *data; }; struct h2 { size_t len; unsigned char data[]; }; 我知道h2的大小就像省略了灵活数组成员(数据),也就是说

在阅读了一些与flexible array member相关的帖子后,我仍然不完全理解为什么我们需要这样一个功能

可能重复:

(如果我没有解决上述可能重复的问题,那就怪我)

以下两种实现之间的实际差异是什么:

struct h1 {
    size_t len;
    unsigned char *data;
};

struct h2 {
    size_t len;
    unsigned char data[];
};
我知道h2的大小就像省略了灵活数组成员(数据),也就是说,
sizeof(h2)==sizeof(size\u t)
。而且我还知道灵活数组成员只能作为结构的最后一个元素出现,因此原始实现在
数据
位置更灵活


我真正的问题是C99为什么要添加此功能?仅仅因为sizeof(h2)不包含数据的实际大小?我肯定我会错过这个功能的一些更重要的要点。请给我指出。

你文章中的两个结构根本没有相同的结构
h1
有一个整数和一个指向char的指针
h2
有一个整数和一个内联字符数组(运行时确定的元素数,可能没有)

换句话说,在
h2
中,字符数据位于结构内部。在
h1
中,它必须位于外部某处

这有很大的不同。例如,如果使用
h1
,则需要注意分配/释放有效负载(除了结构本身)。使用
h2
,只需一次分配/免费,所有内容都打包在一起

使用
h2
可能有意义的一种情况是,如果您正在与某个期望消息以
{length,data}
对的形式进行通信。您可以通过请求
sizeof(h2)+您想要多少有效负载字符来分配
h2
的一个实例,填充它,然后您可以在一次
写入
中传输整个内容(当然要注意endianess等)。如果您使用了
h1
,则需要两个
write
调用(除非您想发送数据的内存地址,这通常没有任何意义)


所以这个特性的存在是因为它很方便。以及各种(有时是不可移植的)技巧,在此之前用于模拟此功能。将其添加到标准中是有意义的。

委员会引入灵活数组成员的主要原因是为了实现著名的结构hack。请参阅下面引用的C99基本原理,特别是第一部分添加的重点

§6.7.2.1结构和联合规范 有一种称为“struct hack”的常用习惯用法,用于创建包含可变大小数组的结构:

struct s
{
int n_items;
/* possibly other fields */
int items[1];
};

struct s *p;
size_t n, i;
/* code that sets n omitted */
p = malloc(sizeof(struct s) + (n - 1) * sizeof(int));
/* code to check for failure omitted */
p->n_items = n;
/* example usage */
for (i = 0; i < p->n_items; i++)
    p->items[i] = i;
结构
{
国际n_项目;
/*可能还有其他领域*/
国际项目[1];
};
结构s*p;
尺寸n,i;
/*省略设置n的代码*/
p=malloc(sizeof(struct s)+(n-1)*sizeof(int));
/*忽略检查故障的代码*/
p->n_项=n;
/*示例用法*/
对于(i=0;in_项;i++)
p->items[i]=i;
这一构想的有效性一直受到质疑。在对一个缺陷的响应中 报告中,委员会决定这是未定义的行为,因为数组
p->items
仅包含一个项目,无论空间是否存在。有人建议采用另一种结构:使数组大小大于最大可能的情况(例如,使用
int items[int_MAX];
),但由于其他原因,这种方法也未定义

委员会认为,尽管没有办法在C89中实现“结构黑客”,但它仍然是一个有用的工具因此引入了“灵活阵列成员”的新功能。除了空括号和在
malloc
调用中删除
“-1”
之外,它的使用方式与struct hack相同,但现在是显式有效的代码。

灵活的数组成员有一些限制,以确保使用它们的代码有意义。例如,必须至少有一个其他成员,灵活数组必须最后出现。类似地,包含灵活数组的结构不能出现在其他结构或数组中。最后,应用于结构的
sizeof
会忽略数组,但会对其前面的任何填充进行计数。这使得
malloc
调用尽可能简单


我不知道这是否被视为重要的一点,但GCC文件指出:

GCC允许灵活数组成员的静态初始化。这相当于定义一个包含原始结构的新结构,然后是一个大小足以包含数据的数组。例如,在下面的例子中,f1的构造就像它被声明为f2一样


(摘自)

谢谢您的回复!根据您的回答,真正酷的是它避免了与有效负载相关的额外alloc/free工作。所以另一个问题是,既然它必须知道
h2
数据的实际大小,为什么我调用
sizeof(h2)
时它选择省略
数据的大小?这与设计更相关,你能帮我吗?:-)“…因为它必须知道…”-谁是“它”?编译器不知道
数据的大小。只有程序员才会这样做。在某些情况下,在为
h2
的实例分配内存后,编译器可能足够聪明,可以推断
数据的大小,但通常不会;p=(结构h2*)malloc(sizeof(结构h2)+len*sizeof(char));p->len=lenfree(p)struct f1 {
    int x; int y[];
} f1 = { 1, { 2, 3, 4 } };

struct f2 {
    struct f1 f1; int data[3];
} f2 = { { 1 }, { 2, 3, 4 } };