简体   繁体   English

如何使用灵活的数组成员初始化结构

[英]How to initialize a structure with flexible array member

I have the following structure我有以下结构

typedef struct _person {
    int age;
    char sex;
    char name[];
}person;

I have done some basic internet search (but unsuccessful) on how to create an instance and initialize a structure with a flexible array member without using malloc() .我已经完成了一些基本的互联网搜索(但未成功),了解如何在不使用malloc()的情况下创建实例并使用灵活的数组成员初始化结构。

For example: for normal structures like例如:对于普通结构,如

struct a {
    int age; 
    int sex;
};

We can create an instance of struct a and initialize it like我们可以创建一个struct a的实例并像这样初始化它

struct a p1 = {10, 'm'};

But for structures with flexible array in it (like _person as mentioned above) how can we create an instance and initialize like how we do it for normal structures ?但是对于其中具有灵活数组的结构(如上面提到的_person ),我们如何创建一个实例并像我们为普通structures所做的那样初始化?

Is it even possible?甚至可能吗? If so, how do we pass the array size during the initialization and the actual value to be initialized?如果是这样,我们如何在初始化期间传递数组大小和要初始化的实际值?

(or) (或者)

Is it true that the only way to create a structure with flexible array is using malloc() as mentioned in C99 specification - 6.7.2.1 Structure and union specifiers - point #17 ?!使用 C99 规范 - 6.7.2.1 Structure and union specifiers - point #17中提到的malloc()创建具有灵活数组的结构的唯一方法是真的吗?

No, flexible arrays must always be allocated manually.不,必须始终手动分配灵活数组。 But you may use calloc to initialize the flexible part and a compound literal to initialize the fixed part.但是您可以使用calloc来初始化灵活部分,并使用复合文字来初始化固定部分。 I'd wrap that in an allocation inline function like this:我将其包装在这样的分配inline函数中:

typedef struct person {
  unsigned age;
  char sex;
  size_t size;
  char name[];
} person;

inline
person* alloc_person(int a, char s, size_t n) {
  person * ret = calloc(sizeof(person) + n, 1);
  if (ret) memcpy(ret,
                  &(person const){ .age = a, .sex = s, .size = n},
                  sizeof(person));
  return ret;
}

Observe that this leaves the check if the allocation succeeded to the caller.请注意,这将检查分配是否成功给调用者。

If you don't need a size field as I included it here, a macro would even suffice.如果您不需要我在这里包含的size字段,那么宏就足够了。 Only that it would be not possible to check the return of calloc before doing the memcpy .只是在执行memcpy之前无法检查calloc的返回。 Under all systems that I programmed so far this will abort relatively nicely.在我到目前为止编程的所有系统下,这将相对较好地中止。 Generally I think that return of malloc is of minor importance , but opinions vary largely on that subject.一般来说,我认为malloc的返回是次要的,但在这个问题上意见差异很大。

This could perhaps (in that special case) give more opportunities to the optimizer to integrate the code in the surroundings:这可能(在那种特殊情况下)为优化器提供更多机会将代码集成到环境中:

#define ALLOC_PERSON(A,  S,  N)                                 \
((person*)memcpy(calloc(sizeof(person) + (N), 1),               \
                 &(person const){ .age = (A), .sex = (S) },     \
                 sizeof(person)))

Edit: The case that this could be better than the function is when A and S are compile time constants.编辑:这可能比函数更好的情况是AS是编译时间常数。 In that case the compound literal, since it is const qualified, could be allocated statically and its initialization could be done at compile time.在这种情况下,复合文字,因为它是const限定的,可以静态分配,并且它的初始化可以在编译时完成。 In addition, if several allocations with the same values would appear in the code the compiler would be allowed to realize only one single copy of that compound literal.此外,如果代码中出现多个具有相同值的分配,则编译器将被允许仅实现该复合文字的一个副本。

There are some tricks you can use.您可以使用一些技巧。 It depends on your particular application.这取决于您的特定应用程序。

If you want to initialise a single variable, you can define a structure of the correct size:如果要初始化单个变量,可以定义正确大小的结构:

   struct  {
        int age;
        char sex;
        char name[sizeof("THE_NAME")];
    } your_variable = { 55, 'M', "THE_NAME" };

The problem is that you have to use pointer casting to interpret the variable as "person"(eg "*(person *)(&your_variable)". But you can use a containing union to avoid this:问题是您必须使用指针转换将变量解释为“person”(例如“*(person *)(&your_variable)”。但是您可以使用包含联合来避免这种情况:

union {
 struct { ..., char name[sizeof("THE_NAME")]; } x;
 person p;
} your_var = { 55, 'M', "THE_NAME" };

so, your_var.p is of type "person".因此,your_var.p 的类型为“person”。 You may also use a macro to define your initializer, so you can write the string only once:你也可以使用宏来定义你的初始化器,这样你就可以只写一次字符串:

#define INIVAR(x_, age_, sex_ ,s_) \
   union {\
     struct { ..., char name[sizeof(s_)]; } x;\
     person p;\
    } x_ = { (age_), (sex_), (s_) }

INIVAR(your_var, 55, 'M', "THE NAME");

Another problem is that this trick is not suitable to create an array of "person".另一个问题是这个技巧不适合创建“人”数组。 The problem with arrays is that all elements must have the same size.数组的问题是所有元素必须具有相同的大小。 In this case it's safer to use a const char * instead of a char[] .在这种情况下,使用const char *而不是char[]更安全。 Or use the dynamic allocation ;)或者使用动态分配;)

A structure type with a flexible array member can be treated as if the flexible array member were omitted, so you can initialize the structure like this.可以将具有灵活数组成员的结构类型视为省略了灵活数组成员,因此您可以像这样初始化结构。

person p = { 10, 'x' };

However, there are no members of the flexible array allocated and any attempt to access a member of the flexible array or form a pointer to one beyond its end is invalid.但是,没有分配灵活数组的任何成员,并且任何访问灵活数组成员或形成指向超出其末尾的指针的任何尝试都是无效的。 The only way to create an instance of a structure with a flexible array member which actually has elements in this array is to dynamically allocate memory for it, for example with malloc .创建具有灵活数组成员的结构实例的唯一方法,该数组成员实际上在该数组中具有元素,是为其动态分配内存,例如使用malloc

You can try typing char name[__flexarr];您可以尝试输入char name[__flexarr]; to resolve the issue.解决问题。

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

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