2011-12-31 126 views
16

我有以下结构如何初始化灵活数组成员的结构

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?!

+1

你不行,struct必须有编译时间大小。 – Anycorn 2011-12-31 10:48:06

+6

@Anycorn:具有灵活数组成员的结构具有编译时间大小。 – 2011-12-31 10:56:09

+3

GCC有一个扩展,允许你做一些像'struct {size_t len; int data []; } x = {4,{1,2,3,4}};'它会起作用,但它不可移植。您可以随时查看平台的'alloca'版本,以获取更可移植的解决方案,但您必须确保它们的行为方式相同,并具有相同的执行方式。 – 2011-12-31 10:58:56

回答

8

不,灵活的数组必须始终手动分配。但是您可以使用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字段,我将它包括在此处,一个宏甚至就足够了。只有在执行memcpy之前不可能检查calloc的退货。在我迄今编程的所有系统中,这将会相当好地中止。一般来说,我认为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

做一个'calloc()'结果的未经检查的副本是危险的;如果分配失败,你会得到一个核心转储(或其他未定义的行为,这不太可能是你想要的)。 – 2011-12-31 16:11:00

+0

@JonathanLeffler,对,将会修改。我将把它集成到函数中。对于marcro,我只会参考我关于检查'malloc'返回值的泛型咆哮。 – 2011-12-31 16:31:47

+0

您的内联功能解决方案非常棒。该宏没有任何优势,恕我直言。这是不可读的,不检查calloc返回值,并且不会表现更好。宏通常不会比内联函数执行得更好(有时甚至更糟 - 考虑将strlen()传递给宏,该宏会对其进行两次评估)。 – ugoren 2011-12-31 17:38:53

2

具有灵活数组成员的结构类型可以像对待灵活数组成员一样被忽略,因此可以像这样初始化结构。

person p = { 10, 'x' }; 

然而,存在分配的柔性阵列和任何尝试访问所述柔性阵列的构件或形成一个指向一个超出其端部是无效的任何成员。用灵活的数组成员创建一个结构实例的唯一方法是在这个数组中实际有元素,例如用malloc为其动态分配内存。

+2

有一个GCC扩展可以让你使用相同的语法指定灵活的数组成员,如果这就是你想要的。 – 2011-12-31 10:59:40

4

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

如果你想初始化一个变量,你可以定义正确尺寸的结构:

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的类型是“人” 的你也可以使用宏定义您的初始化程序,以便您可以编写字符串o只有一次:

#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[]更安全。或者使用动态分配;)