int main()
{
char buffer[5] = { 0 };
buffer[0] = 23;
std::string s(&buffer[0], 4);
std::uint32_t nb = *reinterpret_cast<const std::uint32_t*>(s.data());
return 0;
}
对于这个程序,reinterpret_cast的输出实现是否依赖?或者符合c ++标准的任何编译器是否总能产生相同的输出?
答案 0 :(得分:2)
您正在向std::uint32_t
投射一个缓冲区,该缓冲区未必正确对齐此值。
这可能会爆炸和/或效率极低。
无符号整数类型意味着值表示位的任何位模式都是正常的,而在内置类型的PC平台上,除了值表示位之外没有其他位;特别是没有陷阱位或陷阱总位图。
因此,您可以执行memcpy
并且您可以,技术上 - 只要有足够的字节s.length() >= sizeof(std::uint32_t)
。
然而,如果这种转换发生在普通代码中,那将是一种强烈的代码嗅觉,表明设计中出现了根本性的错误。
附录,关于“或者编译器尊重c ++标准将始终产生相同的输出”。
当我回答的时候,我不知道怎么回事。但简短的回答是,如果转换是以一种有效的方式执行的,例如使用memcpy
,那么它取决于 endianness ,又名字节顺序实际上,整数中最重要或最不重要的部分是否放在最低地址。
实际上,您可以使用从网络字节顺序转换为网络的功能。假设序列化数据的网络字节顺序。查看ntohl
等(这些不是C ++标准库的一部分,但通常可用)。
答案 1 :(得分:2)
对于您的示例代码,如果您正在寻找符合c ++标准的任何编译器始终生成相同的输出&#34;,答案是没有这样的保证
一些简单的例子:对齐问题(如几条评论中所述)和字节序差异。
C ++ 11 5.2.10 / 7&#34;重新解释演员&#34;表示:
可以将对象指针显式转换为对象指针 不同的类型。当“
v
指针”类型的prvalueT1
为时 转换为“指向 cvT2
的指针”,结果是 如果static_cast<cv T2*>(static_cast<cv void*>(v))
和T1
都是标准布局,则为T2
类型(3.9)和T2
的对齐要求并不比。{更严格 那些T1
,或者两种类型都是void
。转换类型的prvalue “指向T1
的指针”指向T2
的指针“(其中T1
和T2
为 对象类型以及T2
的对齐要求为no的位置 比T1
更严格,并回到原来的类型产生 原始指针值。任何其他此类指针的结果 转换未指定。
由于uint32_t
通常会比char[]
具有更严格的对齐要求,因此标准不会对行为作出任何承诺(因为上述内容仅涉及对齐要求的情况)满足)。严格来说,行为是不明确的。
现在,我们假设您只对满足对齐要求的平台感兴趣(即,uint32_t
可以在任何地址上对齐,与char
相同。然后,涉及重新解释演员的表达式等同于(请注意,您必须从const
返回的const char*
中删除std::string::data()
:
std::uint32_t nb = *(static_cast<std::uint32_t*>(static_cast<void*>(const_cast<char*>(s.data()))));
该标准说明了如何在5.2.9 / 13&#34;静态演员&#34;
中使用static_cast
和对象指针(除了类heirarchy中的指针之间的转换)
类型为“指向 cv1
void
的指针”的prvalue可以转换为prvalue 类型为“指向 cv2T
的指针,”其中T
是对象类型而 cv2 是 与 cv1 相同的cv资格,或更高的cv资格。该 空指针值被转换为空指针值 目的地类型。转换为对象的类型指针的值 “指向 cvvoid
的指针”并返回,可能有不同的 cv-qualification,应具有原始值。
因此,就标准而言,您可以对结果指针执行的所有操作都将其强制转换为获取原始值。其他任何东西都是未定义的行为(实现可能会提供更好的保证)。
3.10 / 10&#34; Lvalues和rvalues&#34;允许通过char
或unsigned char
类型访问对象。
但是,重申一下:标准并不保证&#34;任何符合c ++标准的编译器总是产生相同的输出&#34;对于您发布的示例。