2013-02-15 25 views
5

Đây là liên kết bộ nhớ. Trong mã dưới đây, tôi dự kiến ​​rằng bù đắp của b bên trong cấu trúc là 8 (32-bit máy). Xem here. Có, làm cho b luôn xảy ra trong một dòng bộ nhớ cache. Tuy nhiên, đó không phải là trường hợp. Thành viên b trong một đối tượng toàn cầu là struct test1 dường như được căn chỉnh. Tôi không chắc chắn nếu nó của cơ hội hoặc trình biên dịch đang làm điều này cố ý.Tại sao thành viên kép trong cấu trúc không được căn chỉnh trên ranh giới 8 byte?

Tôi muốn hiểu tại sao trình biên dịch không được đệm 4 byte sau a.

struct test1 
{ 
int a; 
double b; 
}t1; 

int main() 
{ 
struct test1 *p = malloc(sizeof(struct test1)); 
printf("sizes int %d, float %d, double %d, long double %d\n", sizeof(int), sizeof(float), sizeof(double), sizeof(long double)); 
printf("offset of b %d\n",(int)&(t1.b)-(int)&(t1)); 

printf("\naddress of b (on heap) = %p, addr of b (on data seg) = %p\n",&(p->b), &(t1.b)); 

return 0; 
} 

Đầu ra là ...

sizes int 4, float 4, double 8, long double 12 
offset of b 4 

address of b (on heap) = 0x804a07c, addr of b (on data seg) = 0x80497e0 

Tôi đang sử dụng trình biên dịch gcc tiêu chuẩn trên ubuntu 10.04

+0

Đối với một điều, nếu CPU có thể đối phó với toán hạng lệch, không có vấn đề . Bây giờ, tại sao trình biên dịch của bạn là cấu trúc đóng gói chặt chẽ, là một câu hỏi. Bạn biên dịch mã như thế nào?Có bất kỳ tùy chọn biên dịch ẩn đến từ makefiles hoặc bất cứ trình biên dịch có thể được kéo từ các tập tin cấu hình của nó? –

+0

@ Alexey, không, chỉ là testC gcc của nó; ./a.out – Chethan

+0

Tôi nhận được kết quả tương tự khi biên dịch với gcc 4.6.3 bằng cách sử dụng tùy chọn "mặc định" và -m32 (Tôi có hệ điều hành 64 bit, do đó mặc định là 64 bit và trong trường hợp đó, mang lại cho tôi sự liên kết 8 byte). –

Trả lời

5

Theo System V ABI for i386, trang 28, double chỉ nhận được 4 byte căn chỉnh, nhưng trình biên dịch cũng được khuyến nghị cung cấp tùy chọn cho 8 byte. Có vẻ như đây là những gì được GCC thực hiện trên Linux, tùy chọn được gọi là -malign-double.

Một lựa chọn khác là sử dụng -m64 để lấy mã đối tượng x86-64, mà đã là mặc định trên một số hệ thống bao gồm cả Mac OS X.

0

Không có đảm bảo về sự liên kết, ở tất cả, trong ANSI C.

Sự liên kết xảy ra với các biến tự động nhiều hơn bất kỳ thứ gì được khai báo trên heap. Nếu bạn đang sử dụng hệ điều hành POSIX, hãy sử dụng memalign (3) để nhận bộ nhớ mà bạn chắc chắn đã căn chỉnh. Malloc có thể trả lại bộ nhớ tại bất kỳ bù đắp nào. Bạn có thể sử dụng các chỉ thị của trình biên dịch như __attribute__ ((__packed__)) để đưa vào các sắp xếp của riêng bạn.

4

Tôi dự kiến ​​rằng độ lệch của b bên trong cấu trúc là 8 (máy 32 bit). Xem tại đây

Tài liệu tham khảo của bạn giải thích lý do tại sao nó có thể thuận lợi cho gấp đôi gấp đôi. Số tiền này không được đảm bảo là số tiền bảo đảm mà đôi sẽ luôn được căn chỉnh 8. Nếu các nguồn của bạn cho biết rằng chúng luôn luôn liên kết 8 và bạn thực hiện một triển khai trong đó chúng không có, thì nguồn của bạn sai.

Từ trang người đàn ông GCC:

Gắn biến "kép" trên ranh giới hai từ sẽ tạo ra mã mà chạy hơi nhanh hơn trên một Pentium tại các chi phí của bộ nhớ hơn.

Vì vậy, lý do của GCC cho 4 liên kết là để tiết kiệm bộ nhớ. Bạn có thể sử dụng -malign-double-mno-align-double để kiểm soát điều đó, mặc dù tất nhiên bạn có nguy cơ tạo ra sự không tương thích nhị phân nếu bạn chia sẻ cấu trúc giữa mã được biên dịch với các tùy chọn xung đột. Đối với các đối tượng/cấu trúc cụ thể, bạn có thể sử dụng riêng __attribute__((aligned)), _Alignas (trong C11) hoặc alignas (trong C++ 11), tất cả đều có thể có hằng số nguyên để xác định căn chỉnh bắt buộc.

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