ブール型が言語ランタイムの間に多くの互換性のない選択肢と市松模様の歴史を持っています。これは、C言語を発明したデニス・リッチーによって作られた歴史的なデザインの選択から始まりました。これにはブール型がありませんでした。代わりの値はintで、値0はfalseを表し、その他の値はtrueと見なされました。
この選択は、ピンボークを使用する主な理由であるWinapiで繰り越さBOOL
れました。Cコンパイラのintのエイリアスであるtypedefがあります。キーワード。明示的な[MarshalAs]属性を適用しない場合、C#ブールはBOOLに変換され、4バイト長のフィールドが生成されます。
何をする場合でも、構造体宣言は、相互運用する言語で行われたランタイムの選択と一致する必要があります。前述のように、winapiのBOOLですが、ほとんどのC ++実装はbyteを選択しました。ほとんどのCOMオートメーション相互運用機能は、VARIANT_BOOLを使用します。ます。 shortです。
C#の実際のサイズbool
は1バイトです。CLRの強力な設計目標は、あなたが見つけることができないことです。レイアウトは、プロセッサーに依存しすぎる実装の詳細です。プロセッサは変数の型と配置に非常に注意深く、間違った選択はパフォーマンスに大きな影響を与え、ランタイムエラーを引き起こす可能性があります。レイアウトを検出不能にすることで、.NETは、実際のランタイム実装に依存しないユニバーサルタイプシステムを提供できます。
言い換えると、レイアウトを明確にするために、実行時に常に構造をマーシャリングする必要があります。その時点で、内部レイアウトから相互運用レイアウトへの変換が行われます。レイアウトが同じ場合は非常に高速になり、フィールドを再配置する必要がある場合は常に構造体のコピーを作成する必要があるため、遅くなる可能性があります。pinvokeマーシャラーは単純にポインターを渡すことができるため、これの専門用語はblittableであり、blittable構造体をネイティブコードに渡すのは高速です。
ブール値が単一ビットではない主な理由もパフォーマンスです。ビットを直接アドレス指定できるプロセッサはほとんどなく、最小単位はバイトです。エクストラ命令が無料で付属していませんバイトのうちのビットを魚に必要とされます。そしてそれは決してアトミックではありません。
それ以外の場合、C#コンパイラは、1バイトを使用することを恥ずかしくないので、を使用しますsizeof(bool)
。これは、フィールドが実行時に取るバイト数の素晴らしい予測値ではありません。CLRも.NETメモリモデルを実装する必要があり、単純な変数の更新がアトミックであることを約束します。そのためには、メモリ内で変数を適切に配置して、プロセッサが1つのメモリバスサイクルで変数を更新できるようにする必要があります。かなり頻繁に、このため、実際にはboolはメモリに4または8バイトを必要とします。次を確実にするために追加された追加のパディングメンバーが適切に配置。
CLRは実際にはレイアウトが検出されないことを利用しており、クラスのレイアウトを最適化してフィールドを再配置し、パディングを最小限に抑えることができます。したがって、bool + int + boolメンバーを持つクラスがある場合、1 +(3)+ 4 + 1 +(3)バイトのメモリが必要です。(3)はパディングで、合計12になります。バイト。50%無駄。自動レイアウトは、1 + 1 +(2)+ 4 = 8バイトに再配置されます。クラスのみに自動レイアウトがあり、構造体にはデフォルトで順次レイアウトがあります。
もっとひどいことに、AVX命令セットをサポートする最新のC ++コンパイラーでコンパイルされたC ++プログラムでは、ブール値が最大32バイトを必要とする場合があります。これは32バイトのアライメント要件を課し、bool変数は31バイトのパディングで終わる可能性があります。また、.NETジッターがSIMD命令を発行しない主な理由は、明示的にラップしない限り、アライメントの保証が得られないためです。