Наложение многомерных массивов

Хорошо известно, что 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 Соответствие

...

  1. ... Неопределенное поведение иным образом обозначено в настоящем международном стандарте словами "неопределенное поведение" или пропуском любого явного определения поведения. Нет разницы в акценте между этими тремя; все они описывают "поведение, которое не определено".
  2. Программа, которая является правильной во всех других аспектах, работает с правильными данными, содержит неопределенное поведение, должна быть правильной программой и действовать в соответствии с 5.1.2.3.
    ...
  3. Строго соответствующая программа должна использовать только те функции языка и библиотеки, которые указаны в настоящем международном стандарте.2) Она не должна создавать выходные данные, зависящие от какого-либо неопределенного, неопределенного или определяемого реализацией поведения, и не должна превышать какого-либо минимального предела реализации.

Насколько я понимаю, совмещение двухмерного массива с одномерным массивом не определено стандартом и, как таковое, приводит к неопределенному поведению. Программа, использующая его, все еще является правильной программой, которая должна быть успешно скомпилирована, но ее вывод не определен

Строго соответствующая программа не должна совмещать 2D-массив с 1D-массивом.

Это, как говорится, общая реализация позволяет и обрабатывать его, как ожидается (что допускается для неопределенного поведения...), чтобы не нарушать унаследованный код, который сильно зависит от него.

Другие вопросы по тегам