Пункт 6.7.3.8 спецификации C99 гласит:
Если спецификация типа массива включает какие-либо квалификаторы типа, то тип элемента определяется так, а не тип массива. Если спецификация типа функции включает в себя какие-либо квалификаторы типа, поведение не определено.
В обосновании (логическая страница 87, физическая страница 94) приведен пример приведения плоского указателя к указателю массива (переменной длины).
void g(double *ap, int n)
{
double (*a)[n] = (double (*)[n]) ap;
/* ... */ a[1][2] /* ... */
}
Конечно, если массив ap
не изменен внутри функции, он должен быть помечен как const, однако приведение в
void g(const double *ap, int n)
{
const double (*a)[n] = (const double (*)[n]) ap;
/* ... */
}
не сохраняет квалификатор const
, поскольку (согласно 6.7.3.8) он применяется к элементам цели вместо самой цели, которая имеет тип массива double[n]
. Это означает, что компиляторы будут справедливо жаловаться, если им будут предоставлены соответствующие флаги (-Wcast-qual
для GCC). Не существует способа обозначить тип массива const
в C, но это приведение очень полезно и «правильно». Флаг -Wcast-qual
полезен для выявления неправильного использования параметров массива, но ложные срабатывания препятствуют его использованию. Обратите внимание, что индексирование a[i][j]
является более читабельным и со многими компиляторами дает лучший машинный код, чем ap[i*n+j]
, поскольку первый позволяет вывести некоторую целочисленную арифметику из внутренних циклов с меньшим количеством анализа.
Должны ли компиляторы рассматривать это как особый случай, эффективно поднимая квалификаторы из элементов в тип массива, чтобы определить, удаляет ли данный приведенный класс квалификаторы или в спецификацию следует внести изменения? Назначение не определено для типов массива, поэтому было бы вредно, чтобы классификаторы всегда применялись к типу массива, а не только к элементам, в отличие от 6.7.3.8?