Các bool loại có một lịch sử ca rô với nhiều sự lựa chọn không tương thích giữa các runtimes ngôn ngữ. Điều này bắt đầu với một lựa chọn thiết kế lịch sử được thực hiện bởi Dennis Ritchie, người đã phát minh ra ngôn ngữ C. Nó không có kiểu bool , thay thế là int trong đó giá trị 0 biểu thị sai và bất kỳ giá trị nào khác được coi là đúng .
Sự lựa chọn này đã được chuyển tiếp trong Winapi, lý do chính để sử dụng pinvoke, nó có một typedef BOOL
là bí danh cho từ khóa int của trình biên dịch C. Nếu bạn không áp dụng thuộc tính [MarshalAs] rõ ràng thì bool C # được chuyển đổi thành BOOL, do đó tạo ra một trường dài 4 byte.
Dù bạn làm gì, khai báo cấu trúc của bạn cần phải phù hợp với lựa chọn thời gian chạy được thực hiện bằng ngôn ngữ bạn giao tiếp. Như đã lưu ý, BOOL cho winapi nhưng hầu hết các triển khai C ++ đều chọn byte , hầu hết interop Tự động hóa COM sử dụng VariANT_BOOL là một đoạn ngắn .
Các thực tế kích thước của một C # bool
là một byte. Mục tiêu thiết kế mạnh mẽ của CLR là bạn không thể tìm ra. Bố cục là một chi tiết thực hiện phụ thuộc vào bộ xử lý quá nhiều. Bộ xử lý rất kén chọn các loại biến và căn chỉnh, các lựa chọn sai có thể ảnh hưởng đáng kể đến hiệu suất và gây ra lỗi thời gian chạy. Bằng cách làm cho bố cục không thể phát hiện được, .NET có thể cung cấp một hệ thống loại phổ quát không phụ thuộc vào việc thực hiện thời gian chạy thực tế.
Nói cách khác, bạn luôn phải sắp xếp một cấu trúc trong thời gian chạy để sắp xếp bố cục. Tại thời điểm chuyển đổi từ bố trí nội bộ sang bố trí interop được thực hiện. Điều đó có thể rất nhanh nếu bố cục giống hệt nhau, chậm khi các trường cần được sắp xếp lại vì điều đó luôn đòi hỏi phải tạo một bản sao của cấu trúc. Thuật ngữ kỹ thuật cho điều này là có thể hiểu được , việc chuyển một cấu trúc có thể xóa được sang mã gốc rất nhanh bởi vì trình sắp xếp pinvoke có thể chỉ đơn giản là vượt qua một con trỏ.
Hiệu suất cũng là lý do cốt lõi tại sao một bool không phải là một bit. Có một vài bộ xử lý làm cho một địa chỉ trực tiếp một chút, đơn vị nhỏ nhất là một byte. Một hướng dẫn bổ sung được yêu cầu để loại bỏ bit ra khỏi byte, điều đó không miễn phí. Và nó không bao giờ là nguyên tử.
Trình biên dịch C # không ngại nói với bạn rằng phải mất 1 byte, hãy sử dụng sizeof(bool)
. Đây vẫn chưa phải là một công cụ dự đoán tuyệt vời cho bao nhiêu byte mà một trường mất trong thời gian chạy, CLR cũng cần thực hiện mô hình bộ nhớ .NET và nó hứa hẹn rằng các cập nhật biến đơn giản là nguyên tử . Điều đó đòi hỏi các biến phải được căn chỉnh chính xác trong bộ nhớ để bộ xử lý có thể cập nhật nó với một chu kỳ bus bộ nhớ duy nhất. Khá thường xuyên, một bool thực sự cần 4 hoặc 8 byte trong bộ nhớ vì điều này. Phần đệm thêm đã được thêm vào để đảm bảo rằng thành viên tiếp theo được căn chỉnh chính xác.
CLR thực sự tận dụng bố cục là không thể phát hiện được, nó có thể tối ưu hóa bố cục của một lớp và sắp xếp lại các trường để phần đệm được giảm thiểu. Vì vậy, giả sử, nếu bạn có một lớp có thành viên bool + int + bool thì sẽ mất 1 + (3) + 4 + 1 + (3) byte bộ nhớ, (3) là phần đệm, tổng cộng là 12 byte. 50% chất thải. Bố cục tự động sắp xếp lại thành 1 + 1 + (2) + 4 = 8 byte. Chỉ có một lớp có bố cục tự động, các cấu trúc có bố cục tuần tự theo mặc định.
Đáng sợ hơn, một bool có thể cần tới 32 byte trong chương trình C ++ được biên dịch với trình biên dịch C ++ hiện đại hỗ trợ tập lệnh AVX. Trong đó áp đặt yêu cầu căn chỉnh 32 byte, biến bool có thể kết thúc với 31 byte đệm. Ngoài ra, lý do cốt lõi khiến jitter .NET không phát ra các hướng dẫn SIMD, trừ khi được gói rõ ràng, nó không thể có được sự đảm bảo căn chỉnh.