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

San*_*raj 22 c struct flexible-array-member

我有以下结构

typedef struct _person {
    int age;
    char sex;
    char name[];
}person;
Run Code Online (Sandbox Code Playgroud)

关于如何创建实例并使用灵活的数组成员初始化结构而不使用,我做了一些基本的互联网搜索(但不成功)malloc().

例如:对于普通结构,如

struct a {
    int age; 
    int sex;
};
Run Code Online (Sandbox Code Playgroud)

我们可以创建一个实例struct a并初始化它

struct a p1 = {10, 'm'};
Run Code Online (Sandbox Code Playgroud)

但是对于具有灵活数组的结构(_person如上所述),我们如何创建一个实例并初始化,就像我们如何正常做一样structures

它甚至可能吗?如果是这样,我们如何在初始化期间传递数组大小以及要初始化的实际值?

(要么)

创建具有灵活数组的结构的唯一方法是使用malloc()C99规范中提到的 - 6.7.2.1 Structure and union specifiers - point #17?!

Jen*_*edt 10

不,必须始终手动分配灵活数组.但是您可以使用calloc初始化柔性部件和复合文字来初始化固定部件.我将它包装在这样的分配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;
}
Run Code Online (Sandbox Code Playgroud)

注意,如果分配成功,则检查是否成功.

如果你不需要size我在这里包含的字段,宏甚至就足够了.只是calloc在做之前不可能检查返回memcpy.在我编程到目前为止的所有系统中,这将相对较好地中止.一般来说,我认为回归malloc是不太重要的,但意见在很大程度上取决于该主题.

这可能(在那种特殊情况下)为优化器提供了更多机会来将代码集成到周围环境中:

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

编辑:这可能是比功能更好的情况是,当AS在编译时间常数.在这种情况下,复合文字,因为它是const合格的,可以静态分配,其初始化可以在编译时完成.此外,如果代码中出现几个具有相同值的分配,则允许编译器仅实现该复合文字的一个副本.

  • 做一个未经检查的`calloc()`结果的副本是危险的; 如果分配失败,您将获得核心转储(或其他未定义的行为,这可能不是您想要的). (2认同)

CB *_*ley 6

具有灵活数组成员的结构类型可以被视为省略了灵活数组成员,因此您可以像这样初始化结构。

person p = { 10, 'x' };
Run Code Online (Sandbox Code Playgroud)

然而,没有分配灵活数组的成员,并且任何访问灵活数组的成员或形成指向超出其末尾的指针的尝试都是无效的。创建具有灵活数组成员(该数组中实际包含元素)的结构实例的唯一方法是为其动态分配内存,例如使用malloc.

  • 有一个 GCC 扩展,可以让您使用相同的语法指定灵活的数组成员(如果您喜欢的话)。 (4认同)

Giu*_*ini 5

你可以使用一些技巧.这取决于您的特定应用.

如果要初始化单个变量,可以定义正确大小的结构:

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

问题是您必须使用指针转换将变量解释为"person"(例如"*(person*)(&your_variable)".但您可以使用包含联合来避免这种情况:

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

所以,your_var.p的类型为"person".您也可以使用宏来定义初始化程序,因此您只能编写一次字符串:

#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");
Run Code Online (Sandbox Code Playgroud)

另一个问题是这个技巧不适合创建一个"人"阵列.数组的问题是所有元素必须具有相同的大小.在这种情况下,使用a const char *而不是a 更安全char[].或者使用动态分配;)