尽管大端计算机并未得到广泛使用,但我想以独立的格式存储双精度数据类型。
对于
int
(或任何整数类型),这非常简单,因为位移位使这非常方便。
int number;
int size=sizeof(number);
char bytes[size];
for (int i=0; i<size; ++i)
bytes[size-1-i] = (number >> 8*i) & 0xFF;
此代码片段以大端格式存储数字,无论其运行在什么机器上。 对 double 执行此操作最优雅的方法是什么?
例如,序列化:
int exp;
unsigned long long mant;
mant = (unsigned long long)(ULLONG_MAX * frexp(number, &exp));
// then serialize exp and mant.
然后反序列化:
// deserialize to exp and mant.
double result = ldexp ((double)mant / ULLONG_MAX, exp);
让其他一切都幸福地忽视这个问题。在其他地方使用当地代表。将双精度浮点数表示为
double
而不是 8 字节数组,将 32 位整数表示为
int
或
int32_t
而不是 4 字节数组,等等。在整个代码中处理字节顺序问题将使您的代码变得臃肿、容易出错且丑陋。
char *src_data;
char *dst_data;
for (i=0;i<N*sizeof(double);i++) *dst_data++=src_data[i ^ mask];
// where mask = 7, if native == low endian
// mask = 0, if native = big_endian
优雅之处在于 mask
,它还可以处理
short
和
int
类型:如果目标和源字节序不同,则为
sizeof(elem)-1
。
std::array<unsigned char, 8> serialize_double( double const* d )
{
std::array<unsigned char, 8> retval;
char const* begin = reinterpret_cast<char const*>(d);
char const* end = begin + sizeof(double);
union
{
uint8 i8s[8];
uint16 i16s[4];
uint32 i32s[2];
uint64 i64s;
} u;
u.i64s = 0x0001020304050607ull; // one byte order
// u.i64s = 0x0706050403020100ull; // the other byte order
for (size_t index = 0; index < 8; ++index)
{
retval[ u.i8s[index] ] = begin[index];
}
return retval;
}
可以处理具有 8 位字符、8 字节双精度和任何疯狂的字节排序的平台(例如,单词中的大端序,但 64 位值的字之间的小端序)。
现在,这不包括双精度数与 64 位整数的字节序不同。
更简单的方法可能是将双精度型转换为 64 位无符号值,然后像输出任何其他 int 一样输出它。
void reverse_endian(double number, char (&bytes)[sizeof(double)])
{
const int size=sizeof(number);
memcpy(bytes, &number, size);
for (int i=0; i<size/2; ++i)
std::swap(bytes[i], bytes[size-i-1]);
}