题
这是来自 这是我之前问题的答案。是否保证编译器能够处理 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++ 标准还规定数组由连续分配的元素组成,这消除了使用指针和填充执行任何奇怪操作的可能性。
其他提示
我认为通过引入 padding 不会有问题 多维的 大批。
数组中的每个元素都必须满足架构所施加的填充要求。数组 [N][M] 在内存中的表示形式始终与 [M*N] 之一相同。
每个数组元素应由编译器按顺序布置在内存中。虽然不同类型的两个声明是相同的底层内存结构。
@康拉德鲁道夫:
我自己把这两个(行专业/列专业)搞混了,但我确实知道这一点:这是明确定义的。
例如,int x[3][5] 是一个大小为 3 的数组,其元素是大小为 5 的 int 数组。(§6.5.2.1) 添加标准中有关数组、寻址等的所有规则。您会发现第二个下标引用连续的整数,而第一个下标将引用连续的 5-int 对象。(所以 3 是较大的数字;你之间有 5 个整数 x[1][0] 和 x[2][0].)
我担心为 Matrix[5][5] 之类的东西添加填充以使每行单词对齐,但这可能只是我自己的迷信。
一个更大的问题是:你真的需要表演这样的演员吗?
虽然你 可能 即使能够摆脱它,完全避免它仍然会更具可读性和可维护性。例如,您可以始终使用 double[m*n] 作为实际类型,然后使用包装此类型的类,并且可能重载 [] 运算符以方便使用。在这种情况下,您可能还需要一个中间类来封装单行——以便 my_matrix[3][5] 之类的代码仍然按预期工作。