reinterpret_cast<>和便携性

reinterpret_cast<> and portabilty

本文关键字:gt lt reinterpret cast      更新时间:2023-10-16

我读到reinterpret_cast<>如果使用不当可能会很危险。所以我相信我使用它是正确的;(。我发现如果我有模板类并且需要类型转换,那么使用它是很好的。但最近我读到reinterpret_cast<>也是不可移植的。我为这一点感到难过。原因是什么?取以下代码,

void Disp(int* val)
{
    for (int i=0; i < SZ; ++i)
    {
        cout << *(val+i) << " ";
    }
    cout << endl;
}
int main()
{
    int arr[SZ];
    Disp(arr);
    unsigned char* ptr = reinterpret_cast<unsigned char*>(arr);
    for (unsigned char* i = ptr; i < (ptr + (SZ * sizeof(int))); i++)
    {
        *i = 0;
    }
    Disp(arr);
    return 0;
}

现在输出:

1174214872 32767 4196789 0 568392584 58 4196720 0 0 0 
0 0 0 0 0 0 0 0 0 0 
Machine type: Linux 2.6.32-358.11.1.el6.x86_64 #1 x86_64 x86_64 x86_64 GNU/Linux

975580 -16506540 -13369152 0 -4202936 67876 3 -4202836 4 -4202828 
0 0 0 0 0 0 0 0 0 0 
Machine type: SunOS DELPHI 5.10 Generic_142900-01 sun4u sparc SUNW,Netra-240

我已经在Linux和Solaris中复制了同一程序的输出。我对便携性问题还不熟悉。所以有人能告诉我,如果我在代码中使用这样的东西,会导致任何可移植性问题吗?即使没有使用此代码,当代码变得复杂(具有动态分配等(并长时间运行时,是否有可能出现意外(未定义的行为(。谢谢你的帮助。

reinterpret_cast<>的可移植性问题在于不同的CPU在内存中存储的数字不同。有些将它们从最低有效字节存储到最高有效字节(little-endian(,而另一些则恰恰相反(big-endian(。有些甚至使用一些奇怪的字节顺序,比如1 0 3 2,不要问我为什么。

无论如何,这样做的结果是,reinterpret_cast<>是可移植的,只要您不以任何方式依赖字节顺序

您的示例代码不依赖于字节顺序,它对所有字节一视同仁(将它们设置为零(,因此代码是可移植的。如果使用reinterpret_cast<>在同一台机器上复制某些数据对象而不解释字节,则代码也将是可移植的(memcpy()可以做到这一点(。

不可移植的是查看第一个字节来确定数字的符号(仅适用于big-endian机器(。如果你试图通过发送reinterpret_cast<char*>的结果将数据从一台机器传输到另一台机器,你也会遇到麻烦:目标机器可能使用与源机器不同的字节顺序,从而完全误解你的数据。

我想说,说reinterpret_cast<>是不可移植的是错误的,它只是将机器细节暴露给特定于机器的C++代码。任何依赖于机器细节的代码都是不可移植的。

此代码存在一些问题。

  • 您正在显示一个未初始化数组的内容。真的没有意义
  • 假设sizeof(int) == 4,您正在对循环的大小进行硬编码。如果您在一台具有不同尺寸int的机器上,这将是不可移植的
  • 如果用零以外的任何值填充内存,则需要担心处理器的字节序

编辑:我看到你已经编辑掉了硬编码的魔术常数4,所以第2点不再适用。

我认为这是可以的。我看到有人认为它是未定义的,因为[basic.lval]#10中允许的别名列表不包括使用int对通过char类型写入的值进行别名。(但也包括与此相反的内容(。

然而,我将"对象的存储值"解释为仍然引用int值,即使在通过char别名写入之后也是如此。这一点在C++标准中似乎没有得到明确的表达;但在C99(这些规则显然是从C99派生的(中,它具有涉及有效类型的不同措辞,该措辞指定存储器的有效类型仍然是int,尽管它是通过char别名写入的。

澄清;在这两种语言中,还有其他规则涉及是否创建陷阱表示的问题。但我看到它认为C++中的严格混叠规则在这种情况下胜过那些规则。

reinterpret_cast<>的可移植性/实用性问题将非常具体地取决于它的使用方式。无论你在什么情况下想要使用玩具,得到玩具示例的答案都不会有帮助

一般来说,如果有一种方法可以在不使用reinterpret_cast<>的情况下完成某件事,那么您应该这样做。使用问题中的示例,您可以使用int* (even though I think that your example's used of interpret_cast<>在不使用reinterpret_cast<>的情况下将数组清除为零is in fact well-defined and portable - using a pointer that has been reinterpret-casted to a char*`是为数不多的可以移植的区域之一(。

在大多数情况下,你可能会发现你需要reinterpret_cast<>,你正在处理一些真正不可移植的东西,你应该理解为什么在特定情况下需要reinterpret_cast<>,并理解特定情况下的可移植性问题。