C 灵活阵列成员的真正好处是什么?
在阅读了一些与flexible array member相关的帖子后,我仍然不完全理解为什么我们需要这样一个功能 可能重复: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的大小就像省略了灵活数组成员(数据),也就是说
(如果我没有解决上述可能重复的问题,那就怪我) 以下两种实现之间的实际差异是什么:
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=len当我想释放它时,我不需要关心有效载荷:free(p)但是,必须有人知道数据的大小,因为它需要释放额外的负载。因为它是k
struct f1 {
int x; int y[];
} f1 = { 1, { 2, 3, 4 } };
struct f2 {
struct f1 f1; int data[3];
} f2 = { { 1 }, { 2, 3, 4 } };