重新解释的值因编译器而异
Reinterpret casted value varies by compiler
对于同一程序:
const char* s = "abcd";
auto x1 = reinterpret_cast<const int64_t*>(s);
auto x2 = reinterpret_cast<const char*>(x1);
std::cout << *x1 << std::endl;
std::cout << x2 << std::endl; // Always "abcd"
在gcc5(链接):139639660962401
在gcc8(链接)中:1684234849
- 为什么值会因编译器版本的不同而不同
- 那么,什么是编译器安全的方式来从const char*移动到int64_t并向后移动(就像在这个问题中一样——不是针对实际的整数字符串,而是包含其他字符的字符串)
- 为什么值会因编译器版本的不同而不同
行为未定义。
- 从const char*向后移动到int64_t的编译器安全方法是什么
"从constchar*移动到int64_t"的意思有些不清楚。基于这个例子,我假设你的意思是创建一个从字符序列(长度不大于fit)到64位整数的映射,这种映射可以使用另一个进程转换回来——可能由另一个(版本)编译器编译。
首先,创建一个int64_t
对象,初始化为零:
int64_t i = 0;
获取字符串的长度
auto len = strlen(s);
检查是否符合
assert(len < sizeof i);
将字符序列的字节复制到整数上
memcpy(&i, s, len);
(只要整数类型没有陷阱表示形式)行为定义良好,只要CPU端序(和负数表示形式)保持不变,生成的整数在编译器版本中就会相同。
读回字符串不需要复制,因为char
在特殊情况下被允许对所有其他类型进行别名:
auto back = reinterpret_cast<char*>(&i);
注意最后一节中的资格。如果整数(例如通过网络)传递给在另一个CPU上运行的进程,则此方法不起作用。这也可以通过比特移位和屏蔽来实现,这样你就可以使用比特移位和掩蔽将八位字节复制到特定的重要位置。
当您取消引用int64_t
指针时,它正在读取为您从中投射的字符串分配的内存末尾。如果将字符串的长度更改为至少8个字节,则整数值将变得稳定。
const char* s = "abcdefg"; // plus null terminator
auto x1 = reinterpret_cast<const int64_t*>(s);
auto x2 = reinterpret_cast<const char*>(x1);
std::cout << *x1 << std::endl;
std::cout << x2 << std::endl; // Always "abcd"
如果您想将指针存储在整数中,则应该使用intptr_t
并省略*
,如:
const char* s = "abcd";
auto x1 = reinterpret_cast<intptr_t>(s);
auto x2 = reinterpret_cast<const char*>(x1);
std::cout << x1 << std::endl;
std::cout << x2 << std::endl; // Always "abcd"
根据RemyLebeau在你的帖子评论中指出的,
unsigned 5_byte_mask = 0xFFFFFFFFFF; std::cout << *x1 & 5_byte_mask << std::endl;
无论使用什么编译器,都应该是在小端序机器上获得相同值的合理方法。根据一个或另一个规范,它可能是UB,但从编译器的角度来看,您正在取消对已初始化五个字节的有效地址处的八个字节的引用,并屏蔽未初始化/垃圾数据的剩余字节。
- 为C++03编译器编写部分unique_ptr,该编译器与较新的编译器在公共代码库上运行
- 如果我想在没有更新编译器的情况下使用新功能,该怎么办?
- 如何强制新操作员根据我的需要解释语句
- C++使用较新的编译器构建应用程序,而无需重新构建库
- VS2019编译器将没有BOM文件的UTF8错误解释为ANSI
- 创建新对象并立即为其设置属性时出现编译器错误
- 编译器包装可解释函数时出错
- 是否有编译器标志可以使较新的 gcc 版本像旧版本一样构建
- 如何向 g++ 编译器解释如何读取用于从'list'文件中搜索 .h 文件的'include'目录列表
- 编译器将输出的流运算符<<解释为用于按位左移的二进制运算符<<
- 自 Visual Studio 15.6.2 编译器更新以来的新 C++17 [[nodiscard]] 警告是否符合标
- 不能在 Solaris 的最新编译器中使用带有新 c+11 标志的 xercesc
- 切换到新编译器后,SSCANF 的工作方式有所不同
- 编译器忽略运算符新分配
- 重新解释的值因编译器而异
- 当我做出语句 root->right->right = newnode(7);注释,编译器显示运行时错误。谁能解释为什么?
- 是否有针对新成员的编译器强化实施完整性的模式
- 类c编译器如何解释if语句
- 编译器如何解释增量前/减量和增量后/减量
- 编译器如何解释这个表达式