联合类型和灵活的数组成员

时间:2013-08-11 19:03:42

标签: c gcc c99

我对C结构中的弹性长度数组有疑问(http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html)。

typedef struct  {
    size_t N;
    int elems[];
} A_t;

现在一般方法很明显,

A_t * a = malloc(sizeof(A_t) + sizeof(int) * N)
a->N = N;
....

现在,当尝试将内容合并到其他结构或基于堆栈的分配时,这似乎很尴尬。因此,对于N!=0

,以下snipet必然会失败
struct {
   A_t a;
   A_t b;    /// !!!!!
   double c; /// !!!!!
};

现在我认为应该可以通过定义另一种类型

来允许这样的用法
typedef struct  {
    size_t N;
    int elems[5];
} A_5_t;

struct {
   A_5_t a;
   A_5_t b;
   double c; // should work here now.
} mystruct;

然后将其用作A_t结构。调用函数void foo(A_t * arg1);时,需要使用foo((A_t*) (&mystruct.b))之类的函数。哪个 - 对我来说 - 似乎有点笨拙。因此,我想知道是否有更好的方法来做到这一点。我想知道是否可以以某种方式使用联合类型?

我问这个问题,因为灵活长度数组可以在结构中将数据整合在一起,因此可以使用单个命令复制结构,而不必担心深度和浅层副本等

3 个答案:

答案 0 :(得分:1)

你有一个多层次的问题。

在这个例子中:

struct {
   A_t b;
   double c; /// fails
};

我会尝试:

 struct {
    double c;
    A_t  b;
 };

始终将结构的变量部分放在末尾。注意,我不使用GCC,所以试试这个,它可能/也许可以工作。

为了跟进@wirrbel给出的要求,以下结构是 NOT 变量长度,但它确实定义并提供对可变长度整数数组的访问。

typedef struct  {
    size_t N;
    int *(elems[]);  // parens to ensure a pointer to an array
} A_t;

A_t *a = malloc //etc.

a->elems = malloc(sizeof(int) * N);

以这种方式,几个A_t结构可以包含在更通用的结构中。

答案 1 :(得分:1)

不,通常您的两个structA_tA_5_t不可互换。原因是具有灵活数组的版本可以在elems字段前面具有与具有固定字段长度的版本不同的填充。

您的编译器是否实现了不同的填充,您可以使用offsetof宏进行测试。但即使您的特定编译器和平台的偏移量相同,如果您需要可移植代码,也最好不要依赖它。

答案 2 :(得分:0)

我现在已经弄清楚了(解决方案实际上已在上面提供的gnu文档中描述)。通过在结构声明之后附加数组声明,可以创建一个与“空”灵活数组直接相邻的连续内存范围。因此,b.A.elems[i]引用与b.elems_[i]相同的数据。

可能建议选择一个标识符,告诉您该数组的内存实际上属于该结构。至少那就是我如何使用它。

typedef struct  {
    size_t N;
    double elems[];
} A_t;
typedef struct {
    A_t a;
    double elems_[4];
} B_t;
void foo(A_t * arg1) {
    for (size_t i=0; i < arg1->N; ++i) {
        printf("%f\n", arg1->elems[i]);
    }
}
int main(int argc, char *argv[]) {
    B_t b;
    b.a.N = 4;
    for (int i=0; i < 4; ++i) {
        b.elems_[i] = 12.4;
    }
    foo(&b.a);
}