29

我有以下结构

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

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

(或者)

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

4

3 回答 3

12

不,必须始终手动分配灵活数组。但是您可以使用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 ofmalloc是次要的,但在这个问题上意见差异很大。

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

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

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

于 2011-12-31T13:13:50.950 回答
7

您可以使用一些技巧。这取决于您的特定应用程序。

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

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

问题是您必须使用指针转换将变量解释为“人”(例如“*(人*)(&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");

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

于 2011-12-31T16:30:20.527 回答
4

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

person p = { 10, 'x' };

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

于 2011-12-31T10:55:09.477 回答