부울 유형은 언어 런타임 사이에는 많은 호환되지 않는 선택과 체크 무늬 역사를 가지고 있습니다. 이것은 C 언어를 발명 한 데니스 리치 (Dennis Ritchie)가 만든 역사적인 디자인 선택으로 시작되었습니다. 부울 유형 이 없었 습니다. 대안은 0 값이 false를 나타내고 다른 값이 true 로 간주 된 int 입니다 .
이 선택은 pinvoke를 사용하는 주된 이유 인 Winapi에서 수행되었으며 BOOL
C 컴파일러의 int 키워드에 대한 별칭 인 typedef 가 있습니다. 명시적인 [MarshalAs] 속성을 적용하지 않으면 C # bool 이 BOOL로 변환되어 4 바이트 길이의 필드가 생성됩니다.
무엇을 하든지 struct 선언은 당신이 사용하는 언어로 만든 런타임 선택과 일치해야합니다. 언급했듯이 winapi의 경우 BOOL이지만 대부분의 C ++ 구현에서는 바이트를 선택했지만 대부분의 COM 자동화 interop은 짧은 VARIANT_BOOL을 사용합니다 .
C # 의 실제 크기 bool
는 1 바이트입니다. CLR의 강력한 디자인 목표는 찾을 수 없다는 것입니다. 레이아웃은 프로세서에 너무 의존하는 구현 세부 사항입니다. 프로세서는 변수 유형 및 정렬에 매우 까다롭기 때문에 잘못된 선택은 성능에 크게 영향을 미치고 런타임 오류를 일으킬 수 있습니다. .NET은 레이아웃을 발견 할 수 없도록하여 실제 런타임 구현에 의존하지 않는 범용 유형 시스템을 제공 할 수 있습니다.
다시 말해, 레이아웃을 구성하려면 런타임에 항상 구조를 마샬링해야합니다. 이때 내부 레이아웃에서 interop 레이아웃으로 변환됩니다 . 레이아웃이 동일하면 매우 빠르며 필드를 다시 정렬해야 할 때 속도가 느릴 수 있습니다. 왜냐하면 항상 구조체의 복사본을 만들어야하기 때문입니다. 이 기술 용어는 blittable PInvoke를 마샬은 단순히 포인터를 전달 할 수 있기 때문에 네이티브 코드에 blittable 구조체를 통과하는 것은 빠르다.
부울 이 단일 비트가 아닌 핵심 이유도 성능입니다 . 직접 주소를 지정할 수있는 프로세서는 거의 없으며 가장 작은 단위는 바이트입니다. 추가 명령이 무료로 제공되지 않는 바이트의 비트를 물고기가 필요합니다. 그리고 그것은 결코 원자 적이 지 않습니다.
C # 컴파일러는 그렇지 않으면 1 바이트가 필요하다는 것을 알려주지 않습니다 sizeof(bool)
. 이것은 필드가 런타임에 몇 바이트를 차지하는 지에 대한 환상적인 예측기는 아니지만 CLR은 .NET 메모리 모델을 구현해야하며 간단한 변수 업데이트가 원자 적이라고 약속합니다 . 따라서 메모리에서 변수를 올바르게 정렬해야 프로세서가 단일 메모리 버스 주기로 변수를 업데이트 할 수 있습니다. 종종 bool은 실제로이 때문에 메모리에 4 또는 8 바이트가 필요합니다. 다음 멤버가 올바르게 정렬 되도록 추가 패딩이 추가되었습니다 .
CLR은 실제로 레이아웃을 발견 할 수 없다는 장점을 가지고 있으며, 클래스의 레이아웃을 최적화하고 필드를 다시 정렬하여 패딩을 최소화 할 수 있습니다. 따라서 bool + int + bool 멤버가있는 클래스가 있으면 1 + (3) + 4 + 1 + (3) 바이트의 메모리가 필요하며 (3)은 패딩입니다. 바이트. 50 % 낭비. 자동 레이아웃은 1 + 1 + (2) + 4 = 8 바이트로 재 배열됩니다. 클래스에만 자동 레이아웃이 있고 구조체에는 기본적으로 순차적 레이아웃이 있습니다.
더 부끄럽게도 bool 은 AVX 명령어 세트를 지원하는 최신 C ++ 컴파일러로 컴파일 된 C ++ 프로그램에서 최대 32 바이트를 요구할 수 있습니다. 32 바이트 정렬 요구 사항을 부과하는 bool 변수는 31 바이트의 패딩으로 끝날 수 있습니다. 또한 .NET 지터가 SIMD 명령을 내 보내지 않는 핵심 이유는 명시 적으로 래핑되지 않으면 정렬 보증을받을 수 없습니다.