2013-09-21 91 views
1

爲什麼需要這段代碼?使用限制結構尺寸:

typedef struct corr_id_{ 
    unsigned int size:8;  
    unsigned int valueType:8; 
    unsigned int classId:8; 
    unsigned int reserved:8;  

} CorrId; 

我對此做了一些調查,發現這種方式我們將內存消耗限制在我們需要的範圍內。 例如

typedef struct corr_id_new{ 
    unsigned int size;  
    unsigned int valueType; 
    unsigned int classId; 
    unsigned int reserved; 

} CorrId_NEW; 

typedef struct corr_id_{ 
    unsigned int size:8;  
    unsigned int valueType:8; 
    unsigned int classId:8; 
    unsigned int reserved:8; 

} CorrId; 

int main(){ 
CorrId_NEW Obj1; 
CorrId  Obj2; 

std::cout<<sizeof(Obj1)<<endl; 
std::cout<<sizeof(Obj2)<<endl; 
} 

輸出: -

16 
4 

我想知道這樣的場景的實際使用情況?爲什麼我們不能聲明這樣的結構,

typedef struct corr_id_new{ 
    unsigned _int8 size;  
    unsigned _int8 valueType; 
    unsigned _int8 classId; 
    unsigned _int8 reserved; 

} CorrId_NEW; 

這是否與編譯器優化有關?或者,以這種方式聲明結構有什麼好處?

+0

實際上你應該結合這兩種方法......或者使用'pack' /'packed' –

+2

你確定輸出是'4 16'而不是'16 4'嗎? –

+0

謝謝。做出了這些改變。 –

回答

1

讓我們來看看一個簡單的場景,

typedef struct student{ 
    unsigned int age:8; // max 8-bits is enough to store a students's age 255 years 
    unsigned int roll_no:16; //max roll_no can be 2^16, which long enough 
    unsigned int classId:4; //class ID can be 4-bits long (0-15), as per need. 
    unsigned int reserved:4; // reserved 

}; 

上述情況下,所有工作都在只有32位完成。

但是,如果你只使用一個整數,它將採取4 * 32位。

如果我們把年齡定爲32位整數,它可以存儲在0到2^32的範圍內。但是不要忘記,一個正常人的年齡只是最大100或140或150(即使是在這個年齡段學習的人也是如此),需要最多8位存儲,所以爲什麼要浪費剩餘的24位。

+0

+20爲您的答案.. :) –

1

它常與pragma pack用於創建標籤位字段,例如:

#pragma pack(0) 

struct eg { 
    unsigned int one : 4; 
    unsigned int two : 8; 
    unsigned int three : 16 
}; 

可投不管出於什麼目的來的int32_t,反之亦然。當讀取(語言不可知的)協議之後的序列化數據時,這可能很有用 - 您提取一個int並將其轉換爲struct eg以匹配協議中定義的字段和字段大小。您也可以跳過轉換,只是將int大小的塊讀入這樣的結構中,指的是位域大小與協議字段大小相匹配。這在網絡編程中非常普遍 - 如果你想在協議之後發送數據包,你只需填充你的結構,序列化和傳輸。

請注意pragma pack不是標準的C,但它被各種常見的編譯器認可。但是,如果沒有編譯指示包,編譯器可以自由地在字段之間放置填充,從而降低上述用途的使用價值。

2

我想了解這種情況的真實用例嗎?

例如,一些CPU的狀態寄存器的結構可能看起來像這樣:

enter image description here

爲了通過結構來表示它,你可以使用位域

struct CSR 
{ 
    unsigned N: 1; 
    unsigned Z: 1; 
    unsigned C: 1; 
    unsigned V: 1; 
    unsigned : 20; 
    unsigned I: 1; 
    unsigned : 2; 
    unsigned M: 5; 
}; 

你可以在這裏看到字段不是8的倍數,所以你不能使用int8_t或類似的東西。

1

你是對的,unsigned _int8的最後結構定義幾乎等於使用​​:8的定義。幾乎,因爲字節順序可以在這裏有所作爲,所以您可能會發現在兩種情況下內存佈局是相反的。

:8符號的主要目的是允許使用小數字節,如

struct foo { 
    uint32_t a:1; 
    uint32_t b:2; 
    uint32_t c:3; 
    uint32_t d:4; 
    uint32_t e:5; 
    uint32_t f:6; 
    uint32_t g:7; 
    uint32_t h:4; 
} 

爲了減少填充,我強烈建議學習填充規則自己,他們並不難理解。如果你這樣做,你可以知道你的版本unsigned _int8沒有添加任何填充。或者,如果您不想學習這些規則,只需在您的結構上使用__attribute__((__packed__)),但這可能會導致嚴重的性能損失。