如何在结构(或等效结构)中定义指向可变长度数组 (VLA) 的指针?

How can I define a pointer to variable length array (VLA) in a struct (or equivalent)?

我在函数中声明了很多指向可变长度数组 (VLA) 的指针以动态分配二维数组;例如,

int M, N; // have some value
double (*arr1)[N] = calloc(M, sizeof(double [N]));
double (*arr2)[N] = calloc(M, sizeof(double [N]));
double (*arr3)[N] = calloc(M, sizeof(double [N]));
... // so many declarations

因为函数变得很长,我试着把它拆分成几个函数,每个函数都需要所有的指针作为参数。我没有在函数中传递很多东西(这对性能不利),而是声明了一个包含全局所有指针的结构以减少参数的数量:

struct ptrpack {
    int M, N;
    double (*arr1)[N];
    double (*arr2)[N];
    ...
};

// then each function just takes a single struct rather than many pointers
void foo(struct ptrpack p) {
    ...
}

但是,结构中不允许指向 VLA 的指针。如果结构定义在函数中,GCC 扩展允许它,但在我的例子中定义在全局范围内。

这个问题的最佳解决方案是什么?我非常喜欢使用指向 VLA 的指针,而不是普通指针。

将结构成员声明为指向未知大小数组的指针(括号中未提供大小表达式):

double (*arr1)[];

此类指针与指向可变长度数组的指针兼容,因为指向兼容类型的指针是兼容的 (C 2018 6.7.6.1 2),并且根据 6.7,未知大小的数组与具有兼容元素类型的任何数组兼容.6.2:

For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value…

由于指针类型不表示数组大小,您将无法直接使用这些成员访问多个维度。例如,如果 p 是结构,p.arr1[i][j] 将产生编译器错误。使用它们的一种方法是将它们分配给包含类型信息的临时变量:

double (*arr1)[p.N] = p.arr1;
… // arr1[i][j] works here.