reinterpret_cast<>和便携性
reinterpret_cast<> and portabilty
我读到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<>
,并理解特定情况下的可移植性问题。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- EASTL矢量<向量<int>>连续的
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在
- 是numeric_limits&lt; int&gt; :: is_modulo从逻辑上矛盾
- opencv 2.4.7在iOS错误背景_segm.hpp #include&lt; list&gt;未找到
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- ///<评论></评论>在Visual Studio中