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

时间:2011-12-31 10:45:56

标签: c struct flexible-array-member

我有以下结构

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

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

例如:对于像

这样的普通结构
struct a {
    int age; 
    int sex;
};

我们可以创建struct a的实例并将其初始化为

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

但对于其中包含灵活数组的结构(如上所述的_person),我们如何创建实例并初始化,就像我们对普通structures的方式进行初始化一样?

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

(或)

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

3 个答案:

答案 0 :(得分:9)

不,必须始终手动分配灵活数组。但是您可以使用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;
}

注意这会留下检查分配是否成功给调用者。

如果您不需要size字段,我将其包含在此处,宏甚至就足够了。只是在执行calloc之前无法检查memcpy的返回。在我编程到目前为止的所有系统中,这将相对较好地中止。一般来说,我认为return of malloc is of minor importance,但意见在很大程度上取决于该主题。

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

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

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

答案 1 :(得分:5)

您可以使用一些技巧。这取决于您的具体应用。

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

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

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

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

所以,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");

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

答案 2 :(得分:2)

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

person p = { 10, 'x' };

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