C++ 如何存储双端独立

C++ 如何存储双端独立,c++,endianness,C++,Endianness,尽管big-endian计算机的应用并不广泛,但我希望以独立格式存储双数据类型 对于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; 整数; int size=sizeof(数字); 字符字节[大小]; 对于(int

尽管big-endian计算机的应用并不广泛,但我希望以独立格式存储双数据类型

对于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;
整数;
int size=sizeof(数字);
字符字节[大小];
对于(int i=0;i>8*i)&0xFF;

此代码snipet以big-endian格式存储数字,尽管它运行在机器上双人间最优雅的方式是什么?

同样。任何数字对象,包括double,最终都是几个字节,根据endianness按特定顺序进行解释。因此,如果您还原字节的顺序,您将在反转的尾数中获得完全相同的值。

char*src\u data;
 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
字符*dst_数据;
对于(i=0;i来说,考虑到格式和可移植性,最好的方法是分别序列化/反序列化尾数和指数。为此,可以使用frexp()/ldexp()函数

例如,要序列化:

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);
然后进行反序列化:

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);

优雅的做法是将endian问题限制在尽可能小的范围内。狭窄的范围是程序与外部世界之间的I/O边界。例如,向其他应用程序发送二进制数据或从其他应用程序接收二进制数据的函数需要注意endian问题,编写从某个数据文件中读取二进制数据。使这些接口认识到表示问题


让所有其他的东西都不知道这个问题。在其他地方使用本地表示法。将双精度浮点数表示为
double
而不是8字节的数组,将32位整数表示为
int
int32_t
而不是4字节的数组,等等。处理代码中的结尾问题会使代码臃肿、容易出错、难看。

不是很好移植,也不符合标准,但类似于:

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;
}
std::数组序列化\u double(双常量*d)
{
std::数组检索;
char const*begin=reinterpret_cast(d);
char const*end=begin+sizeof(双精度);
联合
{
uint8i8s[8];
uint16-i16s[4];
uint32 i32s[2];
uint64 i64s;
}u;
u、 i64s=0x0001020304050607ull;//单字节顺序
//u.i64s=0x070605040300100ull;//另一个字节顺序
对于(大小索引=0;索引<8;++索引)
{
retval[u.i8s[index]]=开始[index];
}
返回返回;
}
可以处理具有8位字符、8字节双精度和任意疯狂字节顺序的平台(例如,对于64位值,单词中的大端号,但单词之间的小端号)

现在,这还不包括double的endianness与64位int的endianness不同

更简单的方法可能是将double转换为64位无符号值,然后像输出任何其他int一样输出该值。

void reverse\u endian(双精度数字、字符和字节)[sizeof(double)]
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]);
}
{ 常量int size=sizeof(数字); memcpy(字节、数量、大小);
对于(int i=0;i使用浮点,您不仅需要担心尾数,还需要担心格式。您可以安全地假设IEEE 754格式吗?是的,让我们这样说:)谢谢您的评论。顺便说一句,对于您的
int
情况,执行
(数字>>(8*i))&0xFF
会更简单。注意,“char”可能与8位大小不同。std::numeric_limits::Digits它至少是8,所以在这种情况下这不会影响我们。谢谢。然后需要找出尾数,例如,将1.0存储到内存中,并检查哪个字节包含7f。是的,这是尾数问题的核心。这对我有什么帮助?不,因为编译器抱怨
>
在双精度上不是有效的操作。@icepack:我不这么认为。(双精度>>8)不如(整数>>8)有效@icepack:无法强制转换。这会导致类型转换。你的意思是类型双关,必须通过内存来完成。类型转换有什么问题?
long
足够大,可以容纳
double
。这真是个好主意,可能会帮助未来的访问者。但在我的情况下,输出格式已经达成一致。它是double p精度IEE 754.+1没错,但i/o本机接口上也存在优雅问题。我说得再好不过了,阿琪:)。我已经在这么做了。