Как я могу определить указатель на массив переменной длины (VLA) в структуре (или эквиваленте)? - PullRequest
0 голосов
/ 02 августа 2020

Я объявил много указателей на массив переменной длины (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 не допускается в struct. Расширение G CC допускает это, если определение структуры находится в функции, но в моем случае определение находится в глобальной области.

Какое лучшее решение этой проблемы? Я настоятельно предпочитаю использовать указатель на VLA, а не обычный указатель.

1 Ответ

2 голосов
/ 02 августа 2020

Объявить элементы структуры как указатели на массивы неизвестного размера (в скобках не указано выражение размера):

double (*arr1)[];

Такие указатели совместимы с указателями на массивы переменной длины, поскольку указатели на совместимые типы совместимы (C 2018 6.7.6.1 2), а массив неизвестного размера совместим с любым массивом с совместимым типом элемента, согласно 6.7.6.2:

Чтобы два типа массивов были совместимы, оба должны иметь совместимые типы элементов, и если оба спецификатора размера присутствуют и являются целочисленными константными выражениями, тогда оба спецификатора размера должны иметь одно и то же постоянное значение…

Поскольку тип указателя не указывает размер массива, вы не сможете использовать эти члены напрямую для доступа к нескольким измерениям. Например, если структура p, то p.arr1[i][j] приведет к ошибке компилятора. Один из способов их использования - назначить их временным переменным, которые включают информацию о типе:

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