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

时间:2013-12-01 08:24:02

标签: c struct flexible-array-member

在阅读了与灵活阵列成员相关的一些帖子后,我仍然不完全理解为什么我们需要这样的功能。

  

可能重复:
  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)不包含实际大小的数据?我相信我必须错过这个功能的一些更重要的观点。请指出我。

3 个答案:

答案 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 } };

(摘自http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html