简体   繁体   English

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

[英]What does it mean to have an incomplete array in a struct?

When I have an array in a struct, the meaning is totally clear to me: When the struct is defined, memory for the whole array is reserved and when I copy the struct, all the array contents is copied. 当我在结构中有一个数组时,对我来说含义很清楚:定义该结构时,将保留整个数组的内存,而当我复制该结构时,将复制所有数组内容。

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

But when I use uint8_t data[] , what does that mean? 但是,当我使用uint8_t data[] ,这是什么意思? I guessed it might be the same as uint8_t *data but it isn't. 我猜想它可能与uint8_t *data相同,但事实并非如此。 When I try to assign to it like this: 当我尝试像这样分配给它时:

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

the compiler gives me 编译器给我

cannot assign array type objects 无法分配数组类型对象

An array of an incomplete type as the last member of a struct is a C99 feature called the flexible array member feature. 作为结构的最后一个成员的不完整类型的数组是一个称为“ 弹性数组成员”功能的C99功能。

In this statement 在此声明中

the_s.m.data = something;

you are trying to assign an array but in C, arrays cannot be assigned. 您正在尝试分配数组,但是在C中,无法分配数组。

Your assumption that data[] is the same as *data is simply incorrect. 您认为data[]*data相同的假设是完全错误的。

An unspecified array length can be used when dynamically allocating a structure that ends in an array, but it never means you get an assignable pointer. 动态分配以数组结尾的结构时,可以使用未指定的数组长度,但这绝不意味着您会获得可分配的指针。

An incomplete array type is a reference to the location where the first item of an array would have been allocated, but does not actually allocate space for that item. 不完整的数组类型是对数组第一项应分配的位置的引用,但实际上并未为该项分配空间。 On some older C compilers, one could get a similar effect by declaring an array of size zero, although doing so has never been legal in any "official" version of the C standard. 在一些较旧的C编译器上,可以通过声明大小为零的数组来获得类似的效果,尽管这样做在C标准的任何“官方”版本中都是不合法的。 The primary use for such declarations is for structures which will be allocated using malloc, calloc, or other similar mechanism; 这种声明的主要用途是使用malloc,calloc或其他类似机制分配的结构; the code which allocates space for the struct will allocate enough extra space to handle the desired number of array items. 为该结构分配空间的代码将分配足够的额外空间来处理所需数量的数组项。

Before incomplete array declarations became legal in C, a common workaround was to declare an array of size 1, and then subtract one from the number of elements to be appended to the struct. 在C中使用不完整的数组声明成为合法之前,通常的解决方法是声明一个大小为1的数组,然后从要追加到该结构的元素数量中减去一个。 For example: 例如:

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);
}

This approach had a couple of icky aspects, however: 但是,此方法有几个棘手的方面:

  1. There's no guarantee that the formula used wouldn't allocate unnecessary extra space. 无法保证所使用的公式不会分配不必要的额外空间。 For example, if sizeof(int)==4, sizeof(mystruct) might get padded out to 20 bytes because of int-alignment requirements. 例如,如果sizeof(int)== 4,则由于int对齐要求,sizeof(mystruct)可能会填充为20个字节。 If name_length is four, the total size allocated should be 24 bytes, but the malloc would ask for 27. 如果name_length为4,则分配的总大小应为24个字节,但malloc要求为27个字节。
  2. Because the maximum legal subscript for an array is the smaller of the dimensioned size or the allocated space, accessing `ms->name[i]` for any value of `i` other than zero would technically be undefined behavior. 因为数组的最大合法下标是尺寸大小或分配的空间中较小的一个,所以从技术上来说,访问ms-> name [i]以获得除零以外的任何i值都是不明确的行为。 It would thus be perfectly legal for a compiler optimize `ms->name[i]` as `ms->name[0]`. 因此,对于编译器将“ ms-> name [i]”优化为“ ms-> name [0]”是完全合法的。 In practice, I wouldn't be surprised if every published C compiler in existence would refrain from performing that optimization when subscripting a single-element array at the end of an indirectly-accessed struct (because whether or not the common implementation of the 'struct hack' is legal, a lot of production code uses it. 在实践中,如果在间接访问的结构的末尾对单个元素数组进行下标时,如果存在的每个已发布的C编译器都避免执行该优化,我不会感到惊讶(因为“结构”的通用实现hack”是合法的,很多生产代码都使用它。

If C compilers had simply not included code to reject zero-size arrays, and the standard had specified that the maximum subscript value for any array is (unsigned int)(size-1), the struct hack would have been much cleaner. 如果C编译器根本没有包含拒绝零尺寸数组的代码,并且标准已指定任何数组的最大下标值为(unsigned int)(size-1),则结构修改会更加整洁。 Unfortunately, the standard wasn't written that way. 不幸的是,标准不是这样写的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM