4

ダブルでビッグエンディアンからリトルエンディアンに変更しようとしています。行く1つの方法は、使用することです

double val, tmp = 5.55;

((unsigned int *)&val)[0] = ntohl(((unsigned int *)&tmp)[1]);
((unsigned int *)&val)[1] = ntohl(((unsigned int *)&tmp)[0]);

しかし、その後、警告が表示されます。

別の方法は次のとおりです。

#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) ) 

val = (double)bswap_64(unsigned long long(tmp)); //or
val = (double)ntohll(unsigned long long(tmp));

しかし、その後、小数を失います。for ループを使用せずに double のビットを交換する良い方法を知っている人はいますか?

4

3 に答える 3

9

私はおそらく次のようなことを試してみます:

template <typename T>
void swap_endian(T& pX)
{
    // should static assert that T is a POD

    char& raw = reinterpret_cast<char&>(pX);
    std::reverse(&raw, &raw + sizeof(T));
}

短くて甘い(そして比較的テストされていない). コンパイラは、必要なすべての最適化を行います。上記はすべての POD タイプに対して明確に定義されており、実装の詳細には依存しません。

引数を変更したくない場合のコピー バージョン:

template <typename T>
T swap_endian_copy(T pX)
{
    swap_endian(pX);
    return pX;
}
于 2010-04-20T08:06:17.807 に答える
2

floatまたはdoubleのバイナリ表現を処理するときに注意すべき重要な落とし穴がいくつかあります。

于 2010-04-20T08:18:28.133 に答える
0

それらを交換することはできませんか?

inline unsigned long long EndianChange( double d )
{
    char ch[8];
    memcpy( ch, &d, 8 );  // Note this will be optimised out completely by pretty much every compiler.
    ch[0] ^= ch[7] ^= ch[0] ^= ch[7]; 
    ch[1] ^= ch[6] ^= ch[1] ^= ch[6];
    ch[2] ^= ch[5] ^= ch[2] ^= ch[5];
    ch[3] ^= ch[4] ^= ch[3] ^= ch[4];

    unsigned long long dRet;
    memcpy( &dRet, ch, 8 ); // Again this will get optimised out.
    return dRet;
};

編集: 指摘したように、スワップされた double のバイトはレジスタにロードされる可能性があるため、そのレジスタから戻すと値が無効になる可能性があるため、この問題を回避するために long long の 64 ビットに格納します。

バイトスワップについては以上です。あなたが何をしようとしているのかはわかりませんが、私が今まで使用したすべてのビッグエンディアンプラットフォームは、バイトオーダーが逆になっているだけで、リトルエンディアンと同じエンコーディングを使用しています。上記のコードは、バイト順を逆にします。ほとんどのコンパイラは、単純にバイト スワップを実行し、バイト スワップされた変数を返し、memcpys を取り除きます。これは、エイリアシングの問題に対処する良い方法です。

于 2010-04-20T07:59:41.650 に答える