2008-09-11 71 views
3

这是从this answer to a previous question of mine来的。 是否保证编译器将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)); 
} 

回答

3

从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++标准还规定,数组由连续分配的元素组成,这消除了使用指针和填充做任何奇怪事情的可能性。

0

我会被添加的东西像矩阵[5] [5],使对准每一行字担心填充,但可能是简单的我自己的迷信。

2

我不认为有一个多维阵列引入的填充有问题。

数组中的每个元素必须满足体系结构施加的填充要求。数组[N] [M]总是与[M * N]中的一个具有相同的内存表示形式。

1

每个数组元素都应该由编译器按顺序放在内存中。这两个声明虽然不同的类型是相同的底层内存结构。

0

更大的问题是:你真的需要执行这样的演员吗?

虽然你可能能够摆脱它,它仍然是更具可读性和可维护性,以避免完全。例如,您可以一直使用double [m * n]作为实际类型,然后使用包装此类型的类,并且可能重载[]运算符以便于使用。在这种情况下,您可能还需要一个中间类来封装单个行 - 这样像my_matrix [3] [5]这样的代码仍可按预期工作。

1

@Konrad鲁道夫:

我掺和进去自己那两个(行大/列为主),但我知道这一点:这是很明确的。例如,int x [3] [5]是一个大小为3的数组,其元素是大小为5的int数组。(§6.5.2.1)从标准关于数组中添加所有规则,寻址,等等,你会得到第二个下标引用连续整数,第一个下标将引用连续的5-int对象。 (所以3是更大的数字;你有5个整数在x [1] [0]和x [2] [0]。)