在阅读了与灵活阵列成员相关的一些帖子后,我仍然不完全理解为什么我们需要这样的功能。
可能重复:
Flexible array members in C - bad?
Is this a Flexible Array Struct Members in C as well?
(如果我没有从上面可能的重复问题解决我的问题,请责备我)
以下两个实现之间的真正差异是什么:
struct h1 {
size_t len;
unsigned char *data;
};
struct h2 {
size_t len;
unsigned char data[];
};
我知道h2的大小就好像省略了灵活的数组成员(数据),即sizeof(h2) == sizeof(size_t)
。而且我也知道灵活的数组成员只能作为结构的最后一个元素出现,因此原始实现在data
的位置可以更灵活。
我真正的问题是为什么C99添加此功能?仅仅因为sizeof(h2)不包含实际大小的数据?我相信我必须错过这个功能的一些更重要的观点。请指出我。
答案 0 :(得分:9)
你帖子中的两个结构根本没有相同的结构。 h1
有一个整数和一个指向char的指针。 h2
有一个整数,字符数组内联(在运行时确定的元素数,可能没有)。
不同地说,在h2
中,字符数据在结构内部。在h1
,它必须在外面的某个地方。
这有很大的不同。例如,如果使用h1
,则需要注意分配/释放有效负载(除了结构本身)。使用h2
时,只需要一个分配/免费,所有内容都打包在一起。
使用h2
可能有意义的一种情况是,如果您正在与期望{length,data}
对形式的消息进行通信。您通过请求h2
来分配sizeof(h2)+how many payload chars you want
的实例,填写它,然后您可以将整个内容转移到一个write
中(注意字节顺序等)。如果您使用过h1
,则需要两次write
次调用(除非您想发送数据的内存地址,这通常没有任何意义)。
所以这个功能存在是因为它很方便。以及之前用于模拟此功能的各种(有时是非便携式)技巧。将其添加到标准中是有道理的。
答案 1 :(得分:6)
委员会介绍灵活阵列成员的主要原因是实施着名的 struct hack 。请参阅C99基本原理的以下引用,特别是我添加重点的部分。
Rationale for International Standard — Programming Languages — C§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;
这种结构的有效性一直是值得怀疑的。在对一个缺陷的回应中 报告,委员会认为它是未定义的行为,因为数组
p->items
不管空间是否存在,只包含一个项目。建议使用另一种结构:使数组大小大于最大可能情况(例如,使用int items[INT_MAX];
),但由于其他原因,此方法也未定义。委员会认为,虽然没有办法在C89中实施“结构黑客”,但它仍然是一个有用的设施。 因此引入了“灵活阵列成员”的新功能。除了空括号以及
“-1”
调用中malloc
的删除之外,它的使用方式与struct hack相同,但现在是明确有效的代码。灵活的数组成员有一些限制,可确保使用它们的代码有意义。例如,必须至少有一个其他成员,并且灵活数组必须最后出现。类似地,包含灵活数组的结构不能出现在其他结构或数组中。最后,应用于结构的
sizeof
忽略了数组,但在它之前计算任何填充。这使得malloc
调用尽可能简单。
答案 2 :(得分:2)
我不知道这是否被认为是重要的一点,但GCC文档指出了这一点:
GCC允许灵活数组成员的静态初始化。这相当于定义一个包含原始结构的新结构,后跟一个足够大小的数组来包含数据。例如。在下文中,f1被构造为好像它被声明为f2。
struct f1 {
int x; int y[];
} f1 = { 1, { 2, 3, 4 } };
struct f2 {
struct f1 f1; int data[3];
} f2 = { { 1 }, { 2, 3, 4 } };