2016-01-07 13 views
11

Khi thực hiện P/Gọi, điều quan trọng là phải thực hiện đối sánh bố cục dữ liệu.Kích thước và sự liên kết của mảng bool cố định C# trong cấu trúc là gì?

Chúng tôi có thể kiểm soát bố cục của cấu trúc bằng cách sử dụng một số thuộc tính.

Ví dụ:

struct MyStruct 
{ 
    public bool f; 
} 

đưa ra một kích thước của 4. Trong khi chúng ta có thể nói với trình biên dịch để làm cho nó một bool 1 byte để phù hợp với C++ loại bool:

struct MyStruct 
{ 
    [MarshalAs(UnmanagedType.I1)] 
    public bool f; 
} 

đưa ra một kích thước của 1.

Điều này có ý nghĩa. Nhưng khi tôi kiểm tra mảng bool cố định, tôi đã bối rối.

unsafe struct MyStruct 
{ 
    public fixed bool fs[1]; 
} 

cho kích thước 4 byte. và

unsafe struct MyStruct 
{ 
    public fixed bool fs[4]; 
} 

vẫn cho kích thước 4 byte. nhưng

unsafe struct MyStruct 
{ 
    public fixed bool fs[5]; 
} 

đưa ra một kích thước của 8.

Dường như trong mảng bool cố định, kích thước của nguyên tố bool vẫn là 1 byte, nhưng sự liên kết là 4 byte. Điều này không phù hợp với mảng C++ bool, mà là 1 byte kích thước và liên kết.

Ai đó có thể giải thích cho tôi về điều này không?

Cập nhật: Cuối cùng tôi tìm ra, lý do là, loại bool trong cấu trúc, thì cấu trúc đó sẽ KHÔNG BAO GIỜ được blittable! Vì vậy, không mong đợi một cấu trúc có kiểu bool bên trong để được bố trí giống như trong C.

Trân trọng, Xiang.

Trả lời

13

A bool khá đặc biệt, nó quay trở lại quyết định của Dennis Ritchie để không cung cấp cho ngôn ngữ C một loại bool. Điều đó đã gây ra rất nhiều tình trạng lộn xộn, ngôn ngữ và các nhà thiết kế hệ điều hành tự thêm nó và tạo ra các lựa chọn không tương thích.

Nó đã được thêm vào Winapi làm kiểu chữ BOOL. Đó là marshaling mặc định nếu bạn không ép buộc loại khác. Typedef-ed là int để giữ cho nó tương thích với C, mất 4 byte khi bạn phát hiện ra. Và căn chỉnh đến 4, như bạn đã phát hiện ra, giống như bất kỳ int nào.

Nó đã được thêm vào C++. Không có một đặc tả kích thước, hầu hết các trình biên dịch C++ đã chọn một byte đơn để lưu trữ. Đáng chú ý nhất là trình biên dịch Microsoft C++ đã làm, khả năng thực hiện nhiều nhất bạn sẽ interop với.

Nó đã được thêm vào COM Automation dưới dạng VARIANT_BOOL. Ban đầu được nhắm mục tiêu như là mô hình mở rộng mới cho Visual Basic để loại bỏ các hạn chế VBX, nó trở nên cực kỳ phổ biến và chỉ là về bất kỳ thời gian chạy ngôn ngữ trên Windows bây giờ hỗ trợ nó. VB trở lại sau đó bị ảnh hưởng nặng nề bởi sự nhạy cảm của hệ điều hành 16 bit, một VARIANT_BOOL mất 2 byte.

Tất cả ba môi trường thời gian chạy gốc có thể là mục tiêu cho interop trong chương trình C#. Rõ ràng các nhà thiết kế CLR đã có một sự lựa chọn rất khó để thực hiện, phải chọn giữa 1, 2 và 4 byte.Không có cách nào để giành chiến thắng, trong khi CLR không có một shot tại đoán tại interop COM, nó không thể biết liệu bạn cố gắng để interop với một api dựa trên C hoặc một chương trình C + +. Vì vậy, họ đã lựa chọn hợp lý duy nhất: không ai trong số họ.

Cấu trúc hoặc loại lớp chứa bool không bao giờ là blittable. Ngay cả khi bạn áp dụng [MarshalAs (UnmanagedType.U1)], cái mà sẽ làm cho nó tương thích với kiểu CLR. Không chắc chắn đó là một quyết định tốt, tuy nhiên đó là quyết định của họ nên chúng tôi sẽ phải đối phó với nó.

Có được cấu trúc dễ vỡ là rất mong muốn, nó tránh sao chép. Nó cho phép mã gốc để truy cập trực tiếp vào đống và chồng được quản lý. Khá nguy hiểm và nhiều tờ khai pinvoke bị hỏng đã bị hỏng heap GC mà không có lợi ích thông thường của cảnh báo từ khóa không an toàn. Nhưng không thể đánh bại tốc độ.

Bạn nhận được cấu trúc blittable theo không sử dụng bool. Sử dụng byte để thay thế. Bạn vẫn có thể lấy lại bool bằng cách gói cấu trúc thành viên bằng thuộc tính. Không sử dụng thuộc tính được tự động triển khai, bạn phải quan tâm đến vị trí của byte. Do đó:

struct MyStruct 
{ 
    private byte _f; 
    public bool f { 
     get { return _f != 0; } 
     set { _f = value ? 1 : 0; } 
    } 
} 

Mã gốc không biết gì về tài sản. Đừng lo lắng về chi phí thời gian chạy cho getter và setter, trình tối ưu hóa jitter làm cho chúng biến mất và chúng biến thành một lệnh CPU đơn.

+0

'bool _f tư nhân; '->' byte _f tư nhân; '? – PetSerAl

+0

Vui vì tôi đã giải thích rõ :) Cảm ơn. –

+0

Cảm ơn, đó là một lời giải thích rất chi tiết. Mặc dù tôi hiểu một thuộc tính trong C++ có thể là một giải pháp mạnh mẽ, nhưng tôi vẫn muốn biết lý do tại sao trong mảng bool cố định C#, nó hoạt động rất lạ, trông giống như kích thước của nó là 1 byte, nhưng liên kết của nó là 4 byte. Bạn có biết những gì ma thuật là đằng sau C# marshaling trên mảng bool cố định nhúng trong cấu trúc? –

-1

Nên hoạt động:

[StructLayout(LayoutKind.Sequential)] 
unsafe struct MyStruct 
{ 
    public fixed bool fs[5]; 
} 
+0

Tôi đã thử nghiệm, thậm chí tôi đã thêm thuộc tính bố cục tuần tự này, bool [3] size = 4, bool [4] size = 4, bool [5] size = 8, giống nhau. –

+0

Tôi cũng vậy :) Bạn đã thử [StructLayout (LayoutKind.Sequential, Pack = 1)]? Có vẻ như ở đâu đó trong dự án bạn có tùy chọn đặt căn chỉnh mặc định cho cấu trúc thành 4 byte – Dmitry

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