2012-08-06 24 views
8

Từ this question người ta có thể bắt đầu tin rằng sự liên kết của một công đoàn không nhỏ hơn sự liên kết lớn nhất của các thành viên riêng lẻ. Nhưng tôi gặp sự cố với loại long long trong gcc/g ++. Các ví dụ đầy đủ có thể được tìm thấy here, nhưng đây là những phần có liên quan cho câu hỏi của tôi:Tại sao việc căn chỉnh thành viên công đoàn dài dài lớn hơn công đoàn/cấu trúc có chứa? Điều này có đúng không?

union ull { 
    long long m; 
}; 

struct sll { 
    long long m; 
}; 


int main() { 
#define pr(v) cout << #v ": " << (v) << endl 
    pr(sizeof(long long)); 
    pr(__alignof__(long long)); 
    pr(sizeof(ull)); 
    pr(__alignof__(ull)); 
    pr(sizeof(sll)); 
    pr(__alignof__(sll)); 
}; 

Điều này dẫn đến kết quả như sau:

sizeof(long long): 8 
__alignof__(long long): 8 
sizeof(ull): 8 
__alignof__(ull): 4 
sizeof(sll): 8 
__alignof__(sll): 4 

Tại sao là sự liên kết của một thành viên đoàn lớn hơn mà của công đoàn có chứa?

[UPDATE]

Theo Keith của câu trả lời alignof là sai ở đây. Nhưng tôi thử nghiệm những điều sau và có vẻ như là alignof cho chúng ta biết sự thật. Xem:

union ull { 
    long long m; 
}; 
long long a; 
char b; 
long long c; 
char d; 
ull e; 
int main() { 
#define pr(v) cout << #v ": " << (v) << endl 
    pr(size_t((void*)&b)); 
    pr(size_t((void*)&c)); 
    pr(size_t((void*)&d)); 
    pr(size_t((void*)&e)); 
    pr(size_t((void*)&c) - size_t((void*)&b)); 
    pr(size_t((void*)&e) - size_t((void*)&d)); 
}; 

Sản lượng:

size_t((void*)&b): 134523840 
size_t((void*)&c): 134523848 
size_t((void*)&d): 134523856 
size_t((void*)&e): 134523860 
size_t((void*)&c) - size_t((void*)&b): 8 
size_t((void*)&e) - size_t((void*)&d): 4 

Vì vậy, sự liên kết của long long kiến ​​8 và sự liên kết của công đoàn chứa long long là 4 trong dữ liệu toàn cầu. Đối với phạm vi địa phương tôi không thể kiểm tra điều này vì có vẻ như trình biên dịch được tự do sắp xếp lại dữ liệu cục bộ - vì vậy mẹo này không hoạt động. Bạn có thể nhận xét về nó không?

[/ UPDATE]

+1

Tôi thấy điều tương tự trên Red Hat, gcc 4.7.0 với '-m32', nhưng * không * với' -m64' (tất cả '8'). – BoBTFish

+1

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023 liên kết đến lỗi gcc tương ứng cho _Alignof (C11). –

Trả lời

7

__alignof__ (đó là một phần mở rộng gcc) không nhất thiết phải báo cáo sự liên kết cần cho một loại. Các bộ vi xử lý

x86, ví dụ: không thực sự yêu cầu nhiều hơn 1 byte căn chỉnh cho bất kỳ loại nào. Việc truy cập đối tượng 4 byte hoặc 8 byte có thể sẽ hiệu quả hơn nếu đối tượng được căn chỉnh từ, nhưng sự căn chỉnh byte là đủ.

Trích dẫn các gcc documentation:

Một số máy không bao giờ thực sự đòi hỏi sự liên kết; chúng cho phép tham chiếu với bất kỳ loại dữ liệu nào ngay cả ở một địa chỉ lẻ. Đối với các máy này, __alignof__ báo cáo căn chỉnh nhỏ nhất mà GCC sẽ cung cấp cho loại dữ liệu , thường theo yêu cầu của ABI mục tiêu.

Nhưng điều đó vẫn không thực sự trả lời câu hỏi. Ngay cả với định nghĩa lỏng lẻo đó, tôi không thể nghĩ ra bất kỳ lý do chính đáng nào cho __alignof__ để chỉ ra một liên kết chặt chẽ hơn cho long long hơn là cho một cấu trúc hoặc công đoàn có chứa long long.

Một phương pháp cầm tay hơn để xác định sự liên kết của một loại là thế này:

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t))) 

Điều này mang lại bù đắp của một thành viên của loại t trong một cấu trúc bao gồm một chart.Sử dụng macro này, chương trình này:

#include <iostream> 
#include <cstddef> 

union ull { 
    long long m; 
}; 

struct sll { 
    long long m; 
}; 

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t))) 

int main() { 
#define pr(v) std::cout << #v ": " << (v) << std::endl 
    pr(sizeof(long long)); 
    pr(__alignof__(long long)); 
    pr(ALIGNOF(long long)); 
    pr(sizeof(ull)); 
    pr(__alignof__(ull)); 
    pr(ALIGNOF(ull)); 
    pr(sizeof(sll)); 
    pr(__alignof__(sll)); 
    pr(ALIGNOF(sll)); 
}; 

sản xuất sản lượng này trên hệ thống của tôi (gcc-4.7, Ubuntu 12.04, x86):

sizeof(long long): 8 
__alignof__(long long): 8 
ALIGNOF(long long): 4 
sizeof(ull): 8 
__alignof__(ull): 4 
ALIGNOF(ull): 4 
sizeof(sll): 8 
__alignof__(sll): 4 
ALIGNOF(sll): 4 

Kết quả chỉ ra bởi tôi ALIGNOF() vĩ mô phù hợp: long long có Căn chỉnh 4 byte và cấu trúc hoặc liên kết chứa long long có căn chỉnh 4 byte.

Tôi nghi ngờ đây là lỗi, hoặc ít nhất là không thống nhất, trong việc thực hiện gcc __alignof__. Nhưng sự mơ hồ của định nghĩa làm cho nó khó mà chắc chắn rằng nó thực sự là một lỗi. It doesn't seem to have been reported.

Cập nhật:

tôi có thể nhảy súng, nhưng tôi vừa gửi một bug report.

earlier bug report, đóng là "INVALID", tương tự, nhưng nó không đề cập đến căn chỉnh của cấu trúc.

Cập nhật 2:

báo cáo lỗi của tôi đã bị đóng cửa như một bản sao của một trong những trước đó. Tôi sẽ yêu cầu làm rõ.

+0

Cảm ơn nhiều vì gợi ý 'ALIGNOF()' này. – PiotrNycz

+0

Tuy nhiên macro này không hoạt động đối với các loại NonPOD vì offsetof không hoạt động với NonPOD (xem http://stackoverflow.com/questions/1129894/why-cant-you-use-offsetof-on-non-pod-strucutures- in-c). Bạn có cơ hội biết giải pháp cho các loại NonPOD không? – PiotrNycz

+0

bạn có thể nhận xét về cập nhật của tôi không. Có vẻ như '__alignof __ (long long) == 8' là chính xác. Và những gì được kiểm tra với 'ALIGNOF' của bạn chỉ là sắp xếp của' long long' trong 'struct' giống với' struct sll {long long m; } '. Có lẽ điều này giúp cho báo cáo lỗi của bạn. – PiotrNycz

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