Приведение между многомерными и одномерными массивами
Вопрос
Это пришло из это ответ на мой предыдущий вопрос.Гарантировано ли, что компилятор обработает array[4][4]
такой же как array[16]
?
Например, будет ли любой из приведенных ниже вызовов api_func()
быть безопасным?
void api_func(const double matrix[4][4]);
// ...
{
typedef double Matrix[4][4];
double* array1 = new double[16];
double array2[16];
// ...
api_func(reinterpret_cast<Matrix&>(array1));
api_func(reinterpret_cast<Matrix&>(array2));
}
Решение
Из стандарта C++, ссылаясь на sizeof
оператор:
При применении к массиву результатом является общее количество байтов в массиве.Это означает, что размер массива
n
элементы этоn
раз больше размера элемента.
Исходя из этого, я бы сказал, что double[4][4]
и double[16]
должно было бы иметь одно и то же основное представление.
То есть, учитывая
sizeof(double[4]) = 4*sizeof(double)
и
sizeof(double[4][4]) = 4*sizeof(double[4])
тогда у нас есть
sizeof(double[4][4]) = 4*4*sizeof(double) = 16*sizeof(double) = sizeof(double[16])
Я думаю, что компилятор, соответствующий стандартам, должен будет реализовать их одинаково, и я думаю, что это не то, что компилятор мог бы случайно сломать.Стандартный способ реализации многомерных массивов работает должным образом.Нарушение стандарта потребует дополнительной работы, которая, скорее всего, не принесет никакой пользы.
Стандарт C++ также утверждает, что массив состоит из смежно размещенных элементов, что исключает возможность каких-либо странных действий с использованием указателей и заполнения.
Другие советы
Я не думаю, что существует проблема с заполнением, возникающим из-за наличия многомерный множество.
Каждый элемент массива должен удовлетворять требованиям к заполнению, установленным архитектурой.Массив [N][M] всегда будет иметь то же представление в памяти, что и массив [M*N].
Каждый элемент массива должен последовательно располагаться в памяти компилятором.Два объявления, хотя и разные типы, имеют одну и ту же базовую структуру памяти.
@Конрад Рудольф:
Я сам путаю эти два (основной ряд/столбец), но знаю следующее:Это четко определено.
Например, int x[3][5] — это массив размером 3, элементами которого являются массивы int размера 5.(§6.5.2.1) Добавление всех правил из стандарта о массивах, адресации и т.д.вы получаете, что второй индекс ссылается на последовательные целые числа, тогда как первый индекс будет ссылаться на последовательные 5-целые объекты.(Итак, 3 — большее число;у тебя 5 инт между х[1][0] и х[2][0].)
Я бы беспокоился о добавлении отступов для таких вещей, как Matrix[5][5], чтобы выровнять каждое слово строки, но это может быть просто мое собственное суеверие.
Более серьезный вопрос:вам действительно нужно выполнять такой актерский состав?
Хотя ты мощь Если бы это сошло с рук, то все равно было бы более читабельно и удобно в сопровождении, если бы его вообще можно было избежать.Например, вы можете последовательно использовать double[m*n] в качестве фактического типа, а затем работать с классом, который является оберткой для этого типа и, возможно, перегрузить оператор [] для простоты использования.В этом случае вам также может понадобиться промежуточный класс для инкапсуляции одной строки, чтобы код типа my_matrix[3][5] по-прежнему работал должным образом.