3

ビッグ エンディアンのコンピューターはあまり広く使用されていませんが、double データ型を独立した形式で格納したいと考えています。

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 に対してこれを行う最もエレガントな方法は何ですか?

4

6 に答える 6

7

移植性とフォーマットを考慮した最善の方法は、仮数部と指数部を別々にシリアライズ/デシリアライズすることです。そのためには、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);
于 2012-11-07T21:32:07.153 に答える
5

エレガントなことは、エンディアンの問題をできるだけ小さな範囲に限定することです。その狭い範囲は、プログラムと外部世界の間の I/O 境界です。たとえば、バイナリ データを他のアプリケーションとの間で送受信する関数は、エンディアンの問題を認識している必要があります。バイナリ データをデータ ファイルに書き込んだり、データ ファイルからバイナリ データを読み取ったりする関数も同様です。これらのインターフェースが表現の問題を認識できるようにします。

他のすべてのものを問題に無知にします。それ以外の場所では、ローカル表現を使用してください。倍精度浮動小数点数doubleを 8 バイトの配列ではなく として表し、32 ビット整数を 4 バイトの配列ではなくintまたはとして表します。int32_tコード全体でエンディアンの問題に対処すると、コードが肥大化し、エラーが発生しやすくなり、見苦しくなります。

于 2012-11-07T21:39:47.557 に答える
1

同じ。double を含む数値オブジェクトは、最終的にエンディアンに従って特定の順序で解釈される数バイトです。したがって、バイトの順序を逆にすると、逆のエンディアンでまったく同じ値が得られます。

于 2012-11-07T21:19:09.187 に答える
1
 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

short 型と integer 型も処理するエレガンスがありmaskます。ターゲットとソースのエンディアンが異なる場合は sizeof(elem)-1 です。

于 2012-11-07T21:19:47.097 に答える
0
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]);
}
于 2012-11-08T16:32:09.477 に答える
0

あまり移植性がなく、標準に違反していますが、次のようなものです。

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 ビット値では単語間のリトル エンディアンなど) のプラットフォームを処理する場合があります。

現在、これは double のエンディアンが 64 ビット int のエンディアンと異なることをカバーしていません。

もっと簡単な方法は、double を 64 ビットの unsigned 値にキャストし、それを他の int と同じように出力することです。

于 2012-11-07T22:01:21.350 に答える