2009-06-11 16 views
6

各ビットが正確でなければならないソフトウェア(CPU用)を書いていますので、__packedは非常に重要です。ユニオンと構造体のパック問題

typedef union{ 
uint32_t raw; 
struct{ 
    unsigned int present:1; 
    unsigned int rw:1; 
    unsigned int user:1; 
    unsigned int dirty:1; 
    unsigned int free:7; 
    unsigned int frame:20; 
} __packed; 
}__packed page_union_t; 

これは私の構造体と共用体です。ただし、動作しません:

page_union_t p; //..... 
//This: 
p.frame=trg_page; 
p.user=user; 
p.rw=rw; 
p.present=present; 
//and this: 
p.raw=trg_page<<12 | user<<2 | rw<<1 | present; 

同じuint32を作成する必要があります。しかし、彼らは同じことを作りません。

私の組合に間違っているとは見えないものがありますか?

答えて

8

あなたの構造体は、唯一の31ビット

+3

うわー: – Earlz

0

あなたは、あなたが最初のケースに残さごみビットで終わるされていないことを確認している、あなたが事前に構造のビットをクリアしていることを言及していないを持っていますか?

// maybe try this 
page_union_t p = {0}; 
6

私の知る限り、構造体のビットが格納される順序は、(すぎるとC89標準)C99規格で定義されていません。おそらく、ビットはあなたが期待したものとは逆の順序にあります。

あなたが得た結果と期待した結果が示されている必要があります。これは診断に役立ちます。使用するコンパイラと実行するプラットフォームも重要です。 、結果を逆フィールドの順序に

p.raw = 0xE014B4B4 
p.raw = 0xA5A5A007 
p.raw = 0x4B4B400E 

のMacOS X 10.4.11(のPowerPC G4)、このコードに

に:

#include <inttypes.h> 
#include <stdio.h> 

typedef union 
{ 
     uint32_t raw; 
     struct 
     { 
       unsigned int present:1; 
       unsigned int rw:1; 
       unsigned int user:1; 
       unsigned int dirty:1; 
       unsigned int free:7; 
       unsigned int frame:20; 
     }; 
} page_union_t; 

int main(void) 
{ 
     page_union_t p = { .raw = 0 }; //..... 
     unsigned trg_page = 0xA5A5A; 
     unsigned user = 1; 
     unsigned rw = 1; 
     unsigned present = 1; 

     p.frame = trg_page; 
     p.user = user; 
     p.rw = rw; 
     p.present = present; 

     printf("p.raw = 0x%08X\n", p.raw); 

     p.raw = trg_page<<12 | user<<2 | rw<<1 | present; 
     printf("p.raw = 0x%08X\n", p.raw); 

     p.raw <<= 1; 
     printf("p.raw = 0x%08X\n", p.raw); 
     return(0); 
} 

を示す結果を生成しますもっと詳しく解説できる:

#include <inttypes.h> 
#include <stdio.h> 

typedef union 
{ 
     uint32_t raw; 
     struct 
     { 
       unsigned int frame:20; 
       unsigned int free:7; 
       unsigned int dirty:1; 
       unsigned int user:1; 
       unsigned int rw:1; 
       unsigned int present:1; 
     }; 
} page_union_t; 

int main(void) 
{ 
     page_union_t p = { .raw = 0 }; //..... 
     unsigned trg_page = 0xA5A5A; 
     unsigned user = 1; 
     unsigned rw = 1; 
     unsigned present = 1; 

     p.frame = trg_page; 
     p.user = user; 
     p.rw = rw; 
     p.present = present; 

     printf("p.raw = 0x%08X\n", p.raw); 

     p.raw = trg_page<<12 | user<<2 | rw<<1 | present; 
     printf("p.raw = 0x%08X\n", p.raw); 

     p.raw <<= 1; 
     printf("p.raw = 0x%08X\n", p.raw); 
     return(0); 
} 

これは、結果を与える:

p.raw = 0xA5A5A00E 
p.raw = 0xA5A5A007 
p.raw = 0x4B4B400E 

ビットフィールド構造が定義されている唯一の31ビット..

2
を有しているため、最下位ビットは、使用されないため、最初の結果が最後の16進数としてEを有しています

ビットの正確な位置が重要な場合は、unsigned char配列に構造体を明示的にパックしてアンパックすることが最も安全です。それ以外のものは実装にも依存します。

struct __attribute__((packed)){ 

} 
+0

C標準の作者が、構造やビットフィールドを非常に明示的なレイアウトで定義できるようにする考えは、コンパイラが指定されたバイトオーダーまたはパッキングはネイティブのものと一致しませんでしたが、少なくとも一致すると効率的なコードを生成することができました(ユーザールーチンを呼び出す非効率なコードを常に生成する必要がありません)。 – supercat

2

はこれを見つけるかもしれない人には参考のため、packed属性を試してみてください。私は愚かだよ...
関連する問題