Наложение многомерных массивов
Хорошо известно, что 2D-массив является массивом массивов, и что по стандарту требуется, чтобы он был непрерывно размещенным непустым набором объектов (6.2.5 Types §20) - объект здесь является одномерным массивом.
Также хорошо известно, что для всех распространенных реализаций справедливо следующее равенство T arr2d[X][Y]
где T - тип, а интегральные константы X и Y:
(char *) &arr2d[i][j] == (char *) &arr2d[0][0] + i * Y * sizeof(T) + j * sizeof(T)
Вышесказанное позволяет подумать, что можно разрешить псевдоним 2D-массива и 1D-массива одинакового размера или даже другого 2D-массива того же общего размера:
Например, следующая программа компилируется и запускается без предупреждений и выдает ожидаемый результат:
#include <stdio.h>
int main() {
int i, j, k=0;
int arr2d[3][4]; // array of 3 array of 4 ints
int *arr1 = &arr2d[0][0]; // pointer to first element of an array of 12 ints (1)
int (*arrx)[3] = (int(*)[3]) arr1; //pointer to first row of an array of arrays of 3 ints
//(2)
for (i=0; i<12; i++) arr1[i] = k++; // (3)
for (i=0; i<3; i++) {
for (j=0; j<4; j++) {
printf("%3d", arr2d[i][j]);
}
putc('\n', stdout);
}
for (i=0; i<4; i++) {
for (j=0; j<3; j++) {
printf("%3d", arrx[i][j]);
}
putc('\n', stdout);
}
return 0;
}
Но:
- строки (1) и (3) псевдоним двумерного массива 3x4 к одномерному массиву 12
- строка (2) создает псевдоним 2D-массива 3x4 для 2D-массива 4x3 (через указатель на int)
Мои вопросы:
- (1) и (3) действительны в соответствии со стандартом C?
- если да, верно ли (2)?
1 ответ
Даже если строгие правила псевдонимов позволяют получить доступ к объекту одного типа из содержащего его объекта, в стандартах есть два элемента, которые говорят о том, что наложение двухмерного массива на одномерный массив одинакового размера недопустимо:
Совместимый тип
6.2.7 Совместимый тип и составной тип
1 Два типа имеют совместимый тип, если их типы совпадают.
...
3 Составной тип может быть построен из двух совместимых типов; это тип, который совместим с обоими типами и удовлетворяет следующим условиям:
- Если один тип является массивом известного постоянного размера, составной тип является массивом этого размера; в противном случае, если один тип является массивом переменной длины, этот тип является составным.
...Эти правила применяются рекурсивно к типам, из которых получены эти два типа.
Соответствие:
4 Соответствие
...
- ... Неопределенное поведение иным образом обозначено в настоящем международном стандарте словами "неопределенное поведение" или пропуском любого явного определения поведения. Нет разницы в акценте между этими тремя; все они описывают "поведение, которое не определено".
- Программа, которая является правильной во всех других аспектах, работает с правильными данными, содержит неопределенное поведение, должна быть правильной программой и действовать в соответствии с 5.1.2.3.
...- Строго соответствующая программа должна использовать только те функции языка и библиотеки, которые указаны в настоящем международном стандарте.2) Она не должна создавать выходные данные, зависящие от какого-либо неопределенного, неопределенного или определяемого реализацией поведения, и не должна превышать какого-либо минимального предела реализации.
Насколько я понимаю, совмещение двухмерного массива с одномерным массивом не определено стандартом и, как таковое, приводит к неопределенному поведению. Программа, использующая его, все еще является правильной программой, которая должна быть успешно скомпилирована, но ее вывод не определен
Строго соответствующая программа не должна совмещать 2D-массив с 1D-массивом.
Это, как говорится, общая реализация позволяет и обрабатывать его, как ожидается (что допускается для неопределенного поведения...), чтобы не нарушать унаследованный код, который сильно зависит от него.