2016-09-22 101 views
0

在處理某些框架結構時,我遇到了一個奇怪的行爲。 我迅速用以下測試它與獨立樣本代碼:奇怪的結構包裝

struct non_alligned_struct 
{ 
    uint8_t flag; 

    // start of uint32 bit fields 
    uint32_t a:2; 
    uint32_t b:2; 
    uint32_t c:1; 
    uint32_t d:1; 
    uint32_t e:1; 
    uint32_t f:1; 
    uint32_t g:3; 
    uint32_t h:1; 
    uint32_t i:1; 
    uint32_t j:3; 
    uint32_t k:3; 
    uint32_t l:1; 
    uint32_t m:1; 
    uint32_t n:1; 
    uint32_t o:1; 
    uint32_t p:3; 
    uint32_t q:2; 
    uint32_t r:1; 
    uint32_t s:1; 
    uint32_t t:2; 
    //4 bytes ends here 

    // shouldn't this start at 5th byte ?? 
    uint16_t u; 

    uint16_t v:13; 
    uint16_t w:3; 

    uint16_t x; 

    uint16_t y:13; 
    uint16_t z:3; 
}; 

int main() 
{ 
    struct non_alligned_struct obj1; 
    void *ptr1 = &obj1; 
    void *ptr2 = &(obj1.u); 
    printf("ptr1: %p, ptr2: %p, ptr2 - ptr1: %d\n", ptr1, ptr2, ptr2 - ptr1); 
    return 0; 
} 

輸出: PTR1:0x7fff3216a620,PTR2:0x7fff3216a626,PTR2 - PTR1:6

問:爲什麼PTR2 - ptr1的應該是6。根據我的計算,它應該是5.此外結構是13個字節,所以它得到4個字節對齊,填充是以奇怪的方式完成的。我通過給成員變量給出隨機值驗證,我觀察到填充在以下大膽地點

00000000進行:01 22 31 10 67 FE FF 86 01 FE FF 86 01

+0

ptr2-ptr1絕對等於6 ... – DigitalNinja

+0

在MSVC中,如果我用'#pragma pack(push,1)'和'#pragma pack(pop)'封裝了'struct',它會給出預期的結果'5'否則'8'。我不得不將'void *'指針改爲'char *',因爲'void *'類型的指針運算是實現定義的。 –

+0

約束違規對'void *'進行算術運算。您的編譯器有義務爲此錯誤發佈診斷。 – EOF

回答

1

位字段的對齊是實現定義的。您的實現似乎使用1或(可能2)字節對齊爲uint32_t字段。結果,flag佔據字節0,並且該位字段佔據字節1..4或2..5。在前一種情況下,u默認爲2字節對齊,將其放在字節6..7處,而在後一種情況下,6..7已經是下一個可用插槽。

+0

從OP中的粗體十六進制轉儲中,我會說位字段是1字節對齊的,而'u'字段是2字節對齊的,就像'uint16_t'的預期一樣。 – rodrigo

1

問題:爲什麼PTR2 - PTR1應6.按我計算它應該是5

C允許實現來之間和在任意量結構元件和任何佈置它們之後插入填充選擇。此外,它沒有指定如何將位字段分配給可尋址存儲單元,也不指定它們分配到的可尋址存儲單元的大小。特別是,就標準而言,聲明的位域類型沒有提及這一點。

在年底,因此,你可以計算出需要多少位u面前代表結構成員,但你無法計算的u什麼偏移應該僅僅基於包含結構的聲明。

實際上,將u定位在距結構起始位置的偶數偏移處並不奇怪。由此可見,在結構體表示中存在一些填充,但由於無法獲取位域的計算地址,所以填充的確切位置難以確定。