2014-08-27 19 views
7

Tôi hiểu rằng có các nền tảng HW nơi bạn cần thêm thông tin để trỏ đến một số char hơn là bạn cần trỏ đến một số int (nền tảng có byte không thể định địa chỉ), để trỏ đến số char. một chỉ số của một byte trong từ). Vì vậy, có thể là sizeof(int*) < sizeof(char*) trên các nền tảng như vậy.Có thể kích thước con trỏ cho các lớp phi công đoàn khác nhau không?

Điều gì đó tương tự có thể xảy ra với con trỏ đến các lớp không công đoàn? C++ cho phép biến đổi trả về các kiểu trên các hàm ảo. Hãy nói rằng chúng tôi có các lớp học như thế này:

struct Gadget 
{ 
    // some content 
}; 


struct Widget 
{ 
    virtual Gadget* getGadget(); 
}; 

Bất kỳ mã trong đó kêu gọi getGadget() phải làm việc khi nhận được một Gadget*, nhưng cùng mã (trên thực tế cùng biên soạn nhị phân code) phải làm việc khi nó nhận được một con trỏ đến một loại có nguồn gốc từ Gadget là tốt (có lẽ một loại được định nghĩa trong một thư viện hoàn toàn khác). Cách duy nhất tôi có thể thấy điều này xảy ra một cách hợp lý là sizeof(T*) == sizeof(U*) đối với tất cả các loại nhóm phi công đoàn TU. Vì vậy, câu hỏi của tôi là, được đưa ra trình biên dịch thực tế (không bao gồm Hell ++ giả định) trên một nền tảng cụ thể, có hợp lý để mong đợi rằng tất cả các con trỏ tới các loại lớp không phải là công đoàn sẽ có cùng kích thước không? Không. Hoặc có thực tế lý do tại sao một trình biên dịch có thể muốn sử dụng các kích thước khác nhau trong khi vẫn tuân thủ các loại trả về biến đổi không?

Trên các nền tảng có "con trỏ" khác nhau tồn tại (chẳng hạn như __near__far), giả sử thuộc tính tương tự được áp dụng cho cả hai.

+0

Lưu ý phụ: Có rất nhiều ví dụ trong thế giới được nhúng nơi con trỏ dữ liệu và con trỏ mã có các kích thước khác nhau. – Lindydancer

+0

@Lindydancer Tất nhiên. Nhưng tôi chỉ hỏi một cách rõ ràng về các con trỏ dữ liệu và chỉ về một tập hợp con của chúng ở đó. – Angew

+0

@Casey 'language-lawyer' đã được thêm và xóa một lần. Bạn có chắc nó có thể áp dụng không? Sau khi tất cả, tôi hỏi về thực hiện thực tế, không phải về một giả thuyết mà sẽ làm theo các lá thư của tiêu chuẩn trong khi làm những điều hoàn toàn ngu ngốc trong thực tế. – Angew

Trả lời

4

C có một yêu cầu khó khăn là tất cả các con trỏ tới tất cả các loại cấu trúc đều có cùng biểu diễn và căn chỉnh.

6.2.5 Các loại

27 [...] Tất cả các con trỏ đến cấu trúc loại sẽ có các yêu cầu đại diện và liên kết tương tự như nhau. [...]

C hiệu quả ++ đòi hỏi khả năng tương thích nhị phân với một thực hiện C, bởi vì các yêu cầu của tiêu chuẩn cho extern "C", vì vậy gián tiếp, điều này đòi hỏi tất cả các con trỏ đến cấu trúc loại mà có giá trị trong C (loại POD, khá nhiều) để có cùng biểu diễn và căn chỉnh trong C++.

Không có yêu cầu nào như vậy đã được thực hiện cho các loại không thuộc POD, do đó, việc triển khai sẽ được phép sử dụng các kích thước con trỏ khác nhau trong trường hợp đó.Bạn cho rằng không thể làm việc, nhưng để làm theo ví dụ của bạn,

struct G { }; 
struct H : G { }; 

struct W 
{ 
    virtual G* f() { ... } 
}; 
struct X : W 
{ 
    virtual H* f() { ... } 
}; 

có thể được dịch sang (pseudo-code)

struct W 
{ 
    virtual G* f() { ... } 
}; 
struct X : W 
{ 
    override G* f() { ... } 
    inline H* __X_f() { return static_cast<H *>(f()); } 
}; 

mà vẫn phù hợp với yêu cầu của ngôn ngữ.

Lý do hợp lệ tại sao hai con trỏ đến các loại cấu trúc có thể không giống nhau khi trình biên dịch C++ được chuyển đến nền tảng có trình biên dịch C hiện có với ABI kém thiết kế. G là loại POD, do đó, G * cần phải chính xác những gì trong C. H không phải là loại POD, vì vậy H * không cần phải khớp với bất kỳ loại C nào.

Để căn chỉnh, điều đó thực sự có thể xảy ra: cái gì thực sự xảy ra là x86-32 ABI trên hệ thống GNU/Linux điển hình yêu cầu các loại số nguyên 64 bit phải được căn chỉnh 32 bit, mặc dù căn chỉnh của bộ xử lý ưu tiên thực sự là 64-bit. Bây giờ có một trình triển khai khác và họ quyết định rằng họ muốn yêu cầu căn chỉnh 64 bit, nhưng bị kẹt nếu họ vẫn muốn tương thích với việc triển khai hiện tại.

Đối với kích thước, tôi không thể nghĩ ra một kịch bản hợp lý trong đó nó sẽ xảy ra, nhưng tôi không chắc liệu đó có phải là thiếu trí tưởng tượng về phía tôi hay không.

+0

Bạn có nghĩ rằng việc thực hiện một thủ thuật như vậy có thể xảy ra ngay cả khi 'G' là một lớp cơ sở ảo không đa hình của' H' và do đó ['static_cast' (hoặc bất kỳ diễn viên nào khác) là không thể được (http: //stackoverflow.com/a/24920749/1782465)? – Angew

+1

@Angew Câu hỏi hay. Có, một thủ thuật như vậy vẫn có thể thực hiện được, nó đơn giản sẽ phải được thực hiện theo cách khác xung quanh: mã giả sẽ là 'override G * f() final {return __X_f(); } virtual H * __X_f() {...} ', và trình biên dịch sẽ phải đảm bảo rằng các phần ghi đè của' f' thực sự sẽ ghi đè lên '__X_f'. – hvd

+1

@ Trên thực tế, suy nghĩ về nó, các trình biên dịch đã cần phải làm điều đó, và thực tế đã làm điều đó, bất cứ khi nào một 'bắt nguồn *' không thể đơn giản được giải thích như là một 'cơ sở *' (bao gồm trong ví dụ của bạn). – hvd

0

Theo tôi hiểu C và C++ giả sử bộ nhớ là byte tuyến tính có thể định địa chỉ. Một số nền tảng (ARM đầu) tuy nhiên nhấn mạnh vào tải trọng liên kết từ và các cửa hàng. Trong trường hợp này, trách nhiệm của trình biên dịch là làm tròn con trỏ tới ranh giới từ và sau đó thực hiện các phép dịch bit cần thiết khi tìm nạp một char.

Nhưng vì tất cả điều này chỉ được thực hiện khi tải và lưu trữ, tất cả các con trỏ vẫn trông giống nhau.

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