2014-10-15 17 views
6

Tôi đã thực hiện đoạn mã sau làm ví dụ.Tại sao uint64_t cần nhiều bộ nhớ hơn 2 uint32_t khi được sử dụng trong lớp? Và làm thế nào để ngăn chặn điều này?

#include <iostream> 

struct class1 
{ 

    uint8_t  a; 
    uint8_t  b; 
    uint16_t c; 
    uint32_t d; 
    uint32_t e; 

    uint32_t f; 
    uint32_t g; 
}; 

struct class2 
{ 

    uint8_t  a; 
    uint8_t  b; 
    uint16_t c; 
    uint32_t d; 
    uint32_t e; 

    uint64_t f; 
}; 

int main(){ 
    std::cout << sizeof(class1) << std::endl; 
    std::cout << sizeof(class2) << std::endl; 
    std::cout << sizeof(uint64_t) << std::endl; 
    std::cout << sizeof(uint32_t) << std::endl; 
} 

in

20 
24 
8 
4 

Vì vậy, nó là khá đơn giản để thấy rằng một uint64_t là lớn như hai uint32_t của, Tại sao lớp 2 sẽ có 4 byte thêm, nếu họ đều giống nhau ngoại trừ việc thay thế hai uint32_t cho một uint64_t.

+5

Căn chỉnh. 'class2' cần phải được liên kết 8 byte. 'class1' không. –

+2

Điều này về cơ bản chỉ xảy ra vì cách bạn xây dựng các lớp học của bạn. Vì 'uint64_t' phải căn chỉnh trình biên dịch cần phải ném vào 4 byte đệm trong' lớp2' (sau biến 'e') – UnholySheep

+3

Bạn cũng có thể sắp xếp lại cấu trúc để có các trường theo thứ tự kích thước giảm dần, sau đó là phần đệm các vấn đề sẽ không xuất hiện vì các trường lớn hơn đã có trên một liên kết byte đẹp và sẽ chuyển các trường đó đến các trường có kích thước nhỏ hơn. –

Trả lời

6

Như đã được chỉ ra, điều này là do padding.

Để tránh điều này, bạn có thể sử dụng

#pragma pack(1) 

class ... { 

}; 
#pragma pack(pop) 

Nó nói với trình biên dịch của bạn để sắp xếp không đến 8 byte, nhưng để một byte. Lệnh pop tắt nó (điều này rất quan trọng, vì nếu bạn làm điều đó trong tiêu đề và ai đó bao gồm tiêu đề của bạn, có thể có lỗi rất lạ)

+0

Câu hỏi đặt ra là "tại sao nó lại xảy ra", không phải "tôi nên làm gì về nó." Đề cập đến '#pragma pack' thực sự là về chủ đề, nhưng bạn cũng nên giải thích (và không chỉ liên kết đến) nguyên nhân thực sự. – Angew

+2

Hoặc có thể thay đổi thứ tự các biến trong định nghĩa lớp học của mình. – UnholySheep

+2

Ngoài ra, '#pragma pack' là trình biên dịch cụ thể (mặc dù nó có thể được hỗ trợ rộng rãi) –

1

Quy tắc căn chỉnh (trên x86 và x86_64) thường là căn chỉnh biến số trên kích thước của nó là.

Nói cách khác, các biến 32-bit được xếp trên 4 byte, biến 64-bit trên 8 byte vv

Các offset của f là 12, vì vậy trong trường hợp uint32_t f không đệm là cần thiết, nhưng khi f là một uint64_t, 4 byte đệm được thêm vào để có được f để căn chỉnh trên 8 byte.

Vì lý do này, tốt hơn là thành viên dữ liệu đặt hàng từ lớn nhất đến nhỏ nhất. Sau đó, sẽ không có bất kỳ nhu cầu cho padding hoặc đóng gói.

Các vấn đề liên quan