在开源中方案一
写道,我正在从文件中读取二进制数据(由另一个程序写入)并输出整数,双精度数,
以及其他各种数据类型。挑战之一是它需要
在两种字节序的 32 位和 64 位机器上运行,这意味着我
最终不得不做相当多的低级操作。我认识一个(非常)
关于类型双关和严格别名的一些知识,并想确保我
以正确的方式做事。
基本上,很容易从 char* 转换为各种大小的 int:
int64_t snativeint64_t(const char *buf)
{
/* Interpret the first 8 bytes of buf as a 64-bit int */
return *(int64_t *) buf;
}
我有一系列支持函数可以根据需要交换字节顺序,例如
作为:
int64_t swappedint64_t(const int64_t wrongend)
{
/* Change the endianness of a 64-bit integer */
return (((wrongend & 0xff00000000000000LL) >> 56) |
((wrongend & 0x00ff000000000000LL) >> 40) |
((wrongend & 0x0000ff0000000000LL) >> 24) |
((wrongend & 0x000000ff00000000LL) >> 8) |
((wrongend & 0x00000000ff000000LL) << 8) |
((wrongend & 0x0000000000ff0000LL) << 24) |
((wrongend & 0x000000000000ff00LL) << 40) |
((wrongend & 0x00000000000000ffLL) << 56));
}
在运行时,程序检测机器的字节序并分配
以上之一指向函数指针:
int64_t (*slittleint64_t)(const char *);
if(littleendian) {
slittleint64_t = snativeint64_t;
} else {
slittleint64_t = sswappedint64_t;
}
现在,当我尝试将 char* 转换为 double 时,棘手的部分就出现了。 ID
喜欢重新使用字节序交换代码,如下所示:
union
{
double d;
int64_t i;
} int64todouble;
int64todouble.i = slittleint64_t(bufoffset);
printf("%lf", int64todouble.d);
然而,一些编译器可以优化掉“int64todouble.i”赋值
并破坏程序。有没有更安全的方法来做到这一点,同时考虑
这个程序必须保持性能优化,而且我
不喜欢编写一组并行转换来将 char* 转换为
直接双倍?如果双关的联合方法是安全的,我应该
重写我的函数(例如 snativeint64_t)来使用它?
我最终使用了史蒂夫·杰索普的答案是因为转换函数重新编写为使用 memcpy,如下所示:
int64_t snativeint64_t(const char *buf)
{
/* Interpret the first 8 bytes of buf as a 64-bit int */
int64_t output;
memcpy(&output, buf, 8);
return output;
}
编译成与我的原始代码完全相同的汇编器:
snativeint64_t:
movq (%rdi), %rax
ret
在这两个版本中,memcpy 版本更明确地表达了我想要做的事情,并且应该适用于即使是最幼稚的编译器。
亚当,你的回答也很棒,我从中学到了很多东西。感谢您发帖!