2009-02-13 44 views
8

Hãy xem xét các loại sau:Liệu "tối ưu hóa cơ sở trống" trong GCC có thể cấu hình không?

struct A {}; 
    struct B : A { int i; }; 

sizeof(A) > 0 theo yêu cầu của tiêu chuẩn.

sizeof(B) phải là 4 do tối ưu hóa cơ sở trống. Tuy nhiên, trên GCC 4.1.1 nó là 5 (Tôi đang sử dụng một gói 1 trong lĩnh vực này). Và không nhất quán - một số tệp của tôi đang nhận được, một số thì không. Không thể chắc chắn những gì khác biệt được nêu ra, chúng tôi có một prjoect lớn.

Trên ba trình biên dịch khác mà tôi đang sử dụng (bởi Microsoft và Freescale), tôi không gặp phải vấn đề này. Việc tối ưu hóa cơ sở trống là tùy chọn rõ ràng, theo số this article.

Có tùy chọn trình biên dịch hoặc pragma để điều chỉnh điều này trong GCC 4.1.1 không? Tôi có thể giải quyết vấn đề nhưng tôi muốn hiểu điều gì đang diễn ra trước. Tôi đã google trong một thời gian và dường như không thể tìm thấy bất cứ điều gì.

Trả lời

10

Điều này luôn xảy ra. Tôi đăng ngay trước khi tôi tìm ra. Có lẽ hành động đăng tải khiến tôi suy nghĩ theo một cách khác ..

Vì vậy, trong câu hỏi của tôi, mẫu đã được đơn giản hơn một chút. Nó thực sự giống như thế này:

struct Base {}; 
struct C1 : Base { int i; } 
struct C2 : Base { C1 c; int i; } 

sizeof (C1) là đúng 4 trên tất cả nền tảng, nhưng sizeof (C2) là 9 thay vì 8 trên GCC. Và ... rõ ràng GCC là thứ duy nhất làm đúng, theo đoạn cuối của bài báo tôi liên kết trong câu hỏi ban đầu. Tôi sẽ trích dẫn nó (từ Nathan Meyers) tại đây:

Có thể tối ưu hóa toàn bộ các tối ưu hóa "subobject rỗng" có liên quan, tuân thủ các thông số kỹ thuật của ABI mà trình biên dịch phải tuân theo. (Jason Merrill chỉ một số trong số này ra cho tôi, năm trở lại.) Ví dụ, xem xét ba cấu trúc thành viên (trống) loại A, B, và C, và một thứ tư không có sản phẩm nào. Họ có thể, một cách phù hợp, tất cả đều chiếm cùng một địa chỉ, miễn là họ không có bất kỳ căn cứ nào chung với nhau hoặc với lớp có chứa. Một lưu ý chung trong thực tế là có thành viên đầu tiên (hoặc duy nhất) của một lớp bắt nguồn từ cùng một cơ sở trống như lớp. Trình biên dịch phải chèn đệm để hai lớp con có các địa chỉ khác nhau. Điều này thực sự xảy ra trong bộ điều hợp lặp có một thành viên interator, cả hai bắt nguồn từ std :: iterator. Một tiêu chuẩn được triển khai không đúng chuẩn :: reverse_iterator có thể hiển thị vấn đề này.

Vì vậy, sự mâu thuẫn mà tôi đã thấy chỉ trong trường hợp tôi có mẫu trên. Mỗi nơi khác tôi bắt nguồn từ một cấu trúc trống là ok.

Đủ dễ dàng để làm việc xung quanh. Cảm ơn tất cả các ý kiến ​​và câu trả lời.

+1

Trình biên dịch Intel nhận được đúng cũng như GCC. MSVC là overagressive và vi phạm các tiêu chuẩn về tối ưu hóa cơ bản trống khi một trong các lớp cơ sở cũng là một lớp cơ sở của thành viên đầu tiên. Tôi đã đăng nhiều quy tắc kỹ lưỡng hơn cho VC++ (2005/2008) và GCC (4.1.1) quy tắc trống tại đây. http://stackoverflow.com/questions/547290/is-the-empty-base-optimization-in-gcc-configurable/919694#919694 – Adisak

0

Vâng, đó không phải là câu trả lời hoàn chỉnh, nhưng GCC Manual đề cập rằng g ++ đôi khi có thể đặt các lớp cơ sở trống ở sai lệch. Xem bit về tùy chọn -Wabi.

1

GCC C++ sau những quy tắc với đệm tiêu chuẩn:

LƯU Ý: __attribute__((__packed__)) hoặc thay đổi bao bì mặc định sẽ sửa đổi các quy tắc.

  • lớp EmptyBase {}; -> sizeof (EmptyBase) == 1

  • Bất kỳ số lượng căn cứ trống nào sẽ ánh xạ tới 0 trong cấu trúc bù trừ miễn là tất cả đều là các loại duy nhất (bao gồm cả việc nuôi dạy con cái).

  • Bố mẹ không có cơ sở trống chỉ đơn giản theo thứ tự được khai báo với chỉ đệm cho căn chỉnh. Nếu thành viên đầu tiên của một lớp dẫn xuất ngay sau căn cứ trống không xuất phát từ bất kỳ căn cứ nào, thì nó được phép bắt đầu tại lần bù lệch phù hợp đầu tiên cho thành viên đó lớn hơn hoặc nhiều hơn. bằng với địa chỉ cơ sở trống - đây có thể là địa chỉ giống với các cơ sở trống. Nếu thành viên đầu tiên của một lớp dẫn xuất ngay sau căn cứ trống không xuất phát từ bất kỳ căn cứ nào, thì nó sẽ bắt đầu tại lần bù lệch phù hợp đầu tiên cho thành viên đó lớn hơn địa chỉ cơ sở trống - - đây không bao giờ là địa chỉ giống như các căn cứ trống.

  • Thành viên là các lớp trống phải mất ít nhất một byte dung lượng lưu trữ trong lớp chứa.


MSVC++ sau những quy tắc:

LƯU Ý: #pragma pack hoặc thay đổi bao bì mặc định sẽ sửa đổi các quy tắc.

  • lớp EmptyBase {}; -> sizeof (EmptyBase) == 1

  • Cách duy nhất một lớp cơ sở trống (hoặc lớp bắt nguồn từ một cơ sở trống) sẽ bắt đầu tại offset 0 (zero) là nếu nó là lớp cơ sở đầu tiên.

  • Lớp không có cơ sở trống sẽ bắt đầu ở lần bù căn chỉnh hợp lệ tiếp theo cho lớp cơ sở.

  • Tất cả các lớp cơ sở trống sẽ có vẻ không lưu trữ hiệu quả trong lớp dẫn xuất và không ảnh hưởng đến bù trừ hiện tại trừ khi được theo sau bởi lớp cơ sở trống khác (hoặc lớp bắt nguồn từ cơ sở trống). nên xem quy tắc sau.

  • Lớp trống cơ sở (hoặc lớp bắt nguồn từ cơ sở trống) theo sau lớp cơ sở trống (hoặc lớp bắt nguồn từ cơ sở trống) sẽ thêm 1 vào vị trí bù hiện tại trước khi đệm vào đúng căn chỉnh cho lớp.

  • Không có lớp đệm (trừ căn chỉnh) giữa lớp cơ sở cuối cùng và thành viên lớp đầu tiên hoặc (các) con trỏ vft. *** LƯU Ý: đây là một tối ưu hóa cơ sở trống quá tích cực có thể phá vỡ tiêu chuẩn C++.

  • Thành viên là các lớp trống phải mất ít nhất một byte dung lượng lưu trữ trong lớp chứa.

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