【问题标题】:Is this C++ code portable? (assuming multidimensional arrays have continuous memory layout)这个 C++ 代码是可移植的吗? (假设多维数组有连续的内存布局)
【发布时间】:2012-05-16 12:26:02
【问题描述】:

首先,如果我犯了任何语法错误等,对不起我的英语......

我的问题是,当我们有一个二维数组时,如果我是对的,从计算机和 C/C++ 的角度来看,它只是一个长的一维数组,索引只是帮助编译器映射到具体地址。

此代码片段在 Visual C++ 中工作,但是我想知道,此代码是否 可移植 并且 符合 标准 (C++98),不会对其他架构和/或操作系统造成意外:

int arr[][3] = { 1, 5, 3, 7, 5, 2, 7, 8, 9 };
const int ARR_NUM = sizeof(arr) / sizeof(int);

int* ptr = reinterpret_cast<int*>(arr);    // NOT: int(*)[][3] !!!
for (int i = 0; i < ARR_NUM; ++i) {
    cout << ptr[i] << endl;
}

【问题讨论】:

  • 我切换了标签,因为 [多维] 的标签 wiki 说要改用 [多维数组]。我建议将 [arrays] 替换为 [language-lawyer] 可能会吸引合适的人。
  • 我会使用 int* p= &arr[0][0] 而不是重新解释演员表
  • @user396672,int * p = arr[0];int * p = &amp;arr[0][0];一样,但肯定更清晰。
  • @Griwes:当然是一样的,但是 &arr[0][0] 代表“第一个 int 的地址”,不需要计算 indirecions :)口味问题...
  • @user396672,那你很奇怪(没有冒犯):P

标签: c++ arrays memory multidimensional-array portability


【解决方案1】:

标准

多维数组的元素是按行优先顺序存储的,所以手动索引是可移植的:

C++98、8.3.4/1:

数组类型的对象包含一个连续分配的非空 T 类型的 N 个子对象的集合。

显然,对于多维数组,这会递归地应用。

但是,reinterpret_cast 的这种用法是不可移植的。标准说 (C++98, 5.2.10/1)

[...] 否则,结果是一个右值和 [...], 数组到指针,[...] 标准转换在 表达式 v.

换句话说,传递arr 会立即触发数组衰减到指向其第一个元素的指针。然后是 (C++98, 5.2.10/3) 包罗万象

reinterpret_cast 执行的映射是实现定义的。

本节的其余部分列出了一些例外情况,指定了始终明确定义的强制转换。鉴于它们都不适用于这里,结论是技术上它是默认实现定义的。

最终结论

从理论上讲,这是不可移植的。实际上,只要架构相同(例如 x86),我当然希望演员能够可靠地工作。

幸运的是,您不必假设这样的事情,因为像 others have mentioned 这样的东西 int* ptr = arr[0] 做同样的事情并保证便携。

【讨论】:

  • 不确定这是不是正确的引用:它谈到 T1T2 是对象,我认为这与指针特别不同。
  • @MatthieuM.:没错,我错过了——数组是 POD,所以不是正确的引用。仍在寻找更好的东西。
  • 根据 Bjarne Stroustrup 的书,reinterpret_cast 是实现定义的,因为它通过创建新的目标指针类型来工作,并将位模式从源类型复制到它。为什么它是实现定义的,因为这可能导致对齐更改,并且在某些系统上,不同指针类型之间的字节数可能不同。这并不意味着(从我的角度来看) reinterpret_cast 不可移植。在这种情况下,这种转换是由实现定义的,但在语义上是有意义的,并且应该在不同系统之间产生相同的行为。
  • 第 8.3.4 节是正确的部分,它严格定义了数组的内存布局,以便相关代码可移植。另请注意,object 指的是任何内存条目,因此它适用于所有类型(它并不意味着类类型)。
  • @Benj:你问的不仅仅是可移植性,还有是否符合标准
【解决方案2】:

如果您想真正严格,reinterpret_cast 在标准中的定义并不十分明确。这在任何地方都适用,但你可以提出一个迂腐的理由来反对它。

使用

int *ptr = arr[0];

为了安全起见。保证连续的数组布局。

【讨论】:

    【解决方案3】:

    如果我没记错的话reinterpret_cast 不是便携式操作。

    【讨论】:

    • 视情况而定。 reinterpret_cast 的某些用途已完全指定。
    【解决方案4】:

    至于假设,多维数组具有连续的内存布局,它符合标准且可移植。从 C 时代开始就是这样,C++ 并没有改变这一点。

    但是,reinterpret_cast 不可移植,因此总体而言,不能保证您的代码在任何地方都能正常工作。

    【讨论】:

    • 首先,那是 C,而不是 C++。其次,该段讨论了数组订阅。 reinterpret_case 在这种情况下应该是实现定义的,但我不确定。
    猜你喜欢
    • 2011-06-18
    • 2022-01-24
    • 2019-07-27
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    • 2016-08-07
    • 2022-01-05
    • 1970-01-01
    相关资源
    最近更新 更多