重新解释铸造值因编译器而异

tan*_*ngy 6 c++ c++11

对于同一个程序:

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"
Run Code Online (Sandbox Code Playgroud)

在gcc5(链接):139639660962401
在gcc8(链接):1684234849

  1. 为什么值根据不同的编译器版本而有所不同?
  2. 什么是编译器安全的方式从const char*移动到int64_t和向后(就像在这个问题 - 不是实际的整数字符串,而是与其他字符一起)?

eer*_*ika 6

  1. 为什么值根据不同的编译器版本而有所不同?

行为未定义.

  1. 什么是编译器安全的方式从const char*移动到int64_t和向后

有点不清楚你的意思是"从const char*移动到int64_t".基于这个例子,我假设您的意思是创建一个从字符序列(长度不超过拟合)到64位整数的映射,其方式可以使用另一个进程转换回来 - 可能由另一个进程(版本的)编译编译器.

首先,创建一个int64_t对象,初始化为零:

int64_t i = 0;
Run Code Online (Sandbox Code Playgroud)

获取字符串的长度

auto len = strlen(s);
Run Code Online (Sandbox Code Playgroud)

检查它是否合适

assert(len < sizeof i);
Run Code Online (Sandbox Code Playgroud)

将字符序列的字节复制到整数上

memcpy(&i, s, len);
Run Code Online (Sandbox Code Playgroud)

(只要整数类型没有陷阱表示)行为定义良好,并且生成的整数在编译器版本中将是相同的,只要CPU字节顺序(和负数表示)保持不变即可.

读回字符串不需要复制,因为char特别允许别名所有其他类型:

auto back = reinterpret_cast<char*>(&i);
Run Code Online (Sandbox Code Playgroud)

请注意上一节中的资格.如果将整数(例如,通过网络)传递给在另一个CPU上运行的进程,则此方法不起作用.这也可以通过位移和屏蔽来实现,这样您就可以使用位移和屏蔽将八位字节复制到特定的重要位置.

  • @okovko:这些将在编译时捕获: `int64_t i = 0;` 不会编译,除非机器是二进制补码,并且 64 位是整数字节。 (2认同)
  • @okovko [除非你这样做](/sf/answers/146891111/)。 (2认同)
  • @okovko 网络只是传输数据的示例之一。肯定有连接 PC 和 DSP 的接口吗?我同意你提到的那些遭遇是罕见的,但并非不可能。 (2认同)