在结构中包含不完整的数组意味着什么?

时间:2012-01-15 20:20:11

标签: c arrays struct

当我在结构中有一个数组时,我的意思是完全清楚的:当定义结构时,保留整个数组的内存,当我复制结构时,所有数组内容都被复制。

typedef struct {
    uint8_t type;
    struct {
        uint8_t length;
        uint8_t data[5];
    } m;
} s;

但是当我使用uint8_t data[]时,这是什么意思?我猜这可能与uint8_t *data相同,但事实并非如此。当我尝试像这样分配它时:

s the_s;
uint8_t something[] = {1, 2, 3};
the_s.m.data = something;

编译器给我

  

无法分配数组类型对象

3 个答案:

答案 0 :(得分:3)

作为结构的最后一个成员的不完整类型的数组是名为灵活数组成员功能的C99功能。

在本声明中

the_s.m.data = something;

您正在尝试分配数组,但在C中,无法分配数组。

答案 1 :(得分:2)

您假设data[]*data相同,这是不正确的。

当动态分配以数组结尾的结构时,可以使用未指定的数组长度,但它绝不意味着您获得可分配的指针。

答案 2 :(得分:2)

不完整的数组类型是对已分配数组的第一项的位置的引用,但实际上并未为该项分配空间。在一些较旧的C编译器中,可以通过声明一个大小为零的数组来获得类似的效果,尽管这样做在C标准的任何“官方”版本中都不合法。此类声明的主要用途是使用malloc,calloc或其他类似机制分配的结构;为struct分配空间的代码将分配足够的额外空间来处理所需数量的数组项。

在C中不完整的数组声明变得合法之前,常见的解决方法是声明一个大小为1的数组,然后从要附加到结构的元素数中减去一个。例如:

struct {
  int this,that,whatever;
  char name[1];
} MYSTRUCT;

void test(char *new_name, int new_name_length)
{
  MYSTRUCT *ms = malloc(sizeof(MYSTRUCT)+new_name_length-1);
  memcpy(ms->name, new_name, new_name_length);
}

然而,这种方法有几个方面:

  1. 无法保证所使用的公式不会分配不必要的额外空间。例如,如果sizeof(int)== 4,则由于对齐要求,sizeof(mystruct)可能会填充到20个字节。如果name_length为4,则分配的总大小应为24字节,但malloc将要求27。
  2. 因为数组的最大合法下标是尺寸大小或分配空间中较小的一个,所以从技术上来说,访问`ms-> name [i]`以获取除“0”以外的任何值是未定义的行为。因此,编译器优化`ms-> name [i]`为`ms-> name [0]`是完全合法的。在实践中,如果现有的每个已发布的C编译器在间接访问的结构的末尾订阅单元素数组时都不会执行该优化,那么我不会感到惊讶(因为是否''结构的常见实现hack'是合法的,很多生产代码都使用它。

如果C编译器根本没有包含拒绝零大小数组的代码,并且标准规定任何数组的最大下标值是(unsigned int)(size-1),那么struct hack会更清晰。不幸的是,标准不是那样写的。