7

ビット フィールド構造をリトル エンディアンからビッグ エンディアン アーキテクチャに変換する必要があります。単純に構造要素を交換すると、バイト境界に問題が発生するため、これを行う最善の方法は何ですか。

Ex構造は次のとおりです。

struct {
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
}; 
4

8 に答える 8

8

32 ビット整数を使用し、and- および bitshift 演算子を使用して情報を抽出できます。それが整っていれば、htonl (ホストからネットワークへ、長い) を簡単に使用できます。ネットワーク バイト オーダーはビッグ エンディアンです。

これはビットフィールドほどエレガントではありませんが、少なくとも自分が何を持っているかを知ることができ、コンパイラが構造をパディングすることを心配する必要はありません。

于 2009-04-07T07:11:07.307 に答える
7

プロセッサのエンディアンは、ビット フィールドの順序付けとは無関係です。同じコンピューター上で 2 つのコンパイラーがビットフィールドに反対の順序を使用する可能性は十分にあります。したがって、これを考えると:

union {
    unsigned char x;
    struct {
        unsigned char b1 : 1;
        unsigned char b2 : 7;
    };
} abc;
abc.x = 0;
abc.b1 = 1;
printf( "%02x\n", abc.x );

詳細なドキュメントを持っていない限り、それが 01 と 80 のどちらを出力するかを知る唯一の方法は、試してみることです。

于 2011-02-25T10:19:06.033 に答える
6

MIPS から Linux/x86 にコードを移植するプロジェクトでは、このようにしました。

struct {

#ifdef __ONE_ENDIANESS__
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
#define _STRUCT_FILLED
#endif /* __ONE_ENDIANESS__ */

#ifdef __OTHER_ENDIANESS__
    unsigned int    b6:1;
    unsigned int    b5:7;
    unsigned int    b4:8;
    unsigned int    b3:7;
    unsigned int    b2:8;
    unsigned int    b1:1;
#define _STRUCT_FILLED
#endif /* __OTHER_ENDIANESS__ */

};

#ifndef _STRUCT_FILLED
#  error Endianess uncertain for struct
#else
#  undef _STRUCT_FILLED
#endif /* _STRUCT_FILLED */

マクロは__ONE_ENDIANESS____OTHER_ENDIANESS__使用したコンパイラに適していたので、どれが適切かを調べる必要があるかもしれません...

于 2009-04-07T07:11:15.967 に答える
1

そこには 2 つの 16 ビット セクションがあります (最初の 3 つのフィールドと最後の 3 つのフィールドは 16 ビットです)。

それはたったの 65536 エントリです。したがって、フィールドのビット反転バージョンを保持するルックアップ テーブルがあります。これを簡単にするために、2 つの 16 ビット フィールドを持つ別の構造体との共用体で構造体をラップしますか?

次のようなもの(テストされていない、私はCコンパイラの近くにいません):

union u {
    struct {
        unsigned int    b1:1;
        unsigned int    b2:8;
        unsigned int    b3:7;
        unsigned int    b4:8;
        unsigned int    b5:7;
        unsigned int    b6:1;
     } bits;
     struct {
        uint16 first;
        uint16 second;
     } words
} ;

unit16 lookup[65536];

/* swap architectures */

void swapbits ( union u *p)
{
   p->words.first = lookup[p->words.first];
   p->words.second = lookup[p->words.second];
}

ルックアップ テーブルの人口は、読者の演習として残されています :)

ただし、コンパイラのドキュメントを注意深く読んでください。C 標準がその構造体を 1 つの単語に収めることを要求しているかどうかはわかりません (ただし、ほとんどのコンパイラはそうすると思います)。

于 2009-04-07T07:03:16.017 に答える
1

チャネル (ファイルまたはネットワーク) と構造の間でこれを行います。私が推奨する方法は、既知の表現でファイル バッファーを構築するコードを記述し、その変換を逆にする読み取りコードを一致させることによって、ファイル I/O を構造体から分離することです。

ビットフィールドは unsigned int として定義されており、sizeof(unsigned int)特に移植性がないため、特定の例を推測するのは特に困難です。

sizeof(int)==4構造体へのポインターを取得し、個々のバイトを並べ替えると、おそらく必要な答えが得られると SWAG と仮定します。

プラットフォームごとに異なる構造体を定義するトリックは機能する可能性がありますが、引用した例では、バイト境界に明確な区切りがないため、分割せずにあるプラットフォームと同等のものを別のプラットフォームで生成することはおそらく不可能です1 つ以上のフィールドを 2 つの部分に分けます。

于 2009-04-07T07:14:04.367 に答える
0

物理的なレイアウトが重要な場合は、ビット フィールドを使用しないでください。これは、より大きなワードが入力される順序が実装定義であるためです。

于 2009-04-08T10:35:40.193 に答える
0

バイトを交換するだけで十分です。バイト内のビット位置は、ビッグ エンディアンとリトル エンディアンで同じです。
例:

char* dest = (char*)&yourstruct;
unsigned int orig = yourstruct;
char* origbytes = (char*)&orig;
dest[0] = origbytes[3];
dest[1] = origbytes[2];
dest[2] = origbytes[1];
dest[3] = origbytes[0];
于 2009-04-07T07:13:10.563 に答える
-3

これを実現するために、私は最終的に解決策を得ました(上記のエパテルの解決策から派生したものもあります)。これは、x86 から Solaris SPARC に変換した場合です。

最初に着信構造を交換し、次に逆の順序で要素を読み取る必要があります。基本的に、構造がどのように配置されているかを調べた後、エンディアンがバイト順とビット順の両方で変化したことがわかりました。ここに疑似コードがあります。

struct orig
{    
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
};

struct temp
{    
    unsigned int    b6:1;
    unsigned int    b5:7;
    unsigned int    b4:8;
    unsigned int    b3:7;
    unsigned int    b2:8;
    unsigned int    b1:1;
}temp;


func (struct orig *toconvert)
{
    struct temp temp_val;
    //Swap the bytes
    swap32byte((u32*)toconvert);
    //Now read the structure in reverse order - bytes have been swapped
    (u32*)&temp_val = (u32 *)toconvert;
    //Write it back to orignal structure
    toconvert->b6=temp_val.b6;
    toconvert->b5=temp_val.b5;
    toconvert->b4=temp_val.b4;
    toconvert->b3=temp_val.b3;
    toconvert->b2=temp_val.b2;
    toconvert->b1=temp_val.b1;

}

いくつかの実験の後、このアプローチは、要素が構造を完全に満たす場合、つまり未使用のビットがない場合にのみ有効であることがわかりました。

于 2009-04-10T03:37:53.883 に答える