3

我对 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

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)). 这——对我来说——似乎有点笨拙。因此,我想知道是否有更好的方法来做到这一点。我想知道是否可以为此使用联合类型?

我在问这个问题,因为灵活长度的数组可以将数据放在结构中的一个片段中,因此可以使用单个命令复制结构,而不必担心深拷贝和浅拷贝等。

4

3 回答 3

1

你有一个多层次的问题。

在这个例子中:

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

我会尝试:

 struct {
    double c;
    A_t  b;
 };

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

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

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结构可以包含在更一般的结构中。

于 2013-08-11T19:11:21.903 回答
1

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

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

于 2013-08-11T21:45:27.213 回答
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);
}
于 2013-08-11T21:41:47.443 回答