2011年1月1日 星期六

union 和 struct 的差異

我想union 和 struct 是一個很好用的語法


不過小細節最好還是要弄清楚一點比較好


以下做了一下點這方面的比較


以C30的compiler 為例


 


ex1:


以這樣的範例來說,應該不會有人有問題吧


union {
 unsigned int word;
 struct _field_1
 {
  unsigned int a:5;
  unsigned int b:4;
  unsigned int c:7; 
 }field_1; 
}union_int_1;


假設


union_int_1.field_1.a=0x1;
union_int_1.field_1.b=0x1;
union_int_1.field_1.c=0x1;


那麼


union_int_1.word 會等於0x0221;


沒錯


這是我們要的答案


 


ex2:


union {
 unsigned int word;
 struct _field_2
 {
  unsigned char a:5;
  unsigned char b:4;
  unsigned char c:7; 
 }field_2; 
}union_int_2;


 


假設


union_int_2.field_2.a=0x1;
union_int_2.field_2.b=0x1;
union_int_2.field_2.c=0x1;


那麼


union_int_1.word 會等於0x0101;


沒錯


這不是我們想要的答案,這樣就會出現問題了


問題出在,因為結構的關系,當要做bit field 的設定時,field a 與field b 2者超過8個bit (1個byte),那麼compiler 會自動利用16個bit(1個word)做處理。


所以,這次compiler 對於這個struct 會產生 3個byte 出來,對於union 來說,只能mapping 到2個byte,但多出來的1個byte 就獨自使用了


如果今天不使用到union_int_1.word 這樣的用法時,是不會產生bug,但如果不注意的話,肯定會花一段時間找bug (因為我就是過來人= =)


 


ex3:


union {
 unsigned int word;
 struct _field_3
 {
  unsigned char a:4;
  unsigned char b:4;
  unsigned char c:8; 
 }field_3; 
}union_int_3;


假設


union_int_3.field_3.a=0x1;
union_int_3.field_3.b=0x1;
union_int_3.field_3.c=0x1; 


那麼


union_int_1.word 會等於0x0111;


這也會是我們要的答案


 


有了上面的實驗結果,那麼我們是不是可以把bit field 的宣告都設為unsigned int (16bit) 這樣就好了


當然沒有錯,是可以都這樣使用,但如果你要做聯結的動作只有unsigned char (8bit) 那就會有另一個課題了


 


ex4:


union {
 unsigned char byte;
 struct _field_4
 {
  unsigned char a:4;
  unsigned char b:4;
 }field_4; 
}union_int_4;


ex5:
union {
 unsigned char byte;
 struct _field_5
 {
  unsigned int a:4;
  unsigned int b:4;
 }field_5; 
}union_int_5;


 


有興趣的可以比較2者所做的結果,這裡所做的結果都會一樣,但是在compiler的時後 ex5 會比 ex4  還要多浪費1個byte ,如果當老闆在和你要求code size 和 ram size 時,你就知道又要準備被釘了= =


PS:小細節不可馬虎,太重要了