ブール値が1バイトではなく1バイトなのはなぜですか?


127

C ++では、

  • ブール値が1バイトではなく1バイトなのはなぜですか?
  • 4ビットまたは2ビットの整数のような型がないのはなぜですか?

CPUのエミュレーターを作成するときに上記のことを逃しています


10
C ++では、ビットフィールドを使用してデータを「パック」できます。struct Packed { unsigned int flag1 : 1; unsigned int flag2: 1; };。ほとんどのコンパイラはfullを割り当てunsigned intますが、読み取り/書き込みの際にビットトゥイドルリングを自分で処理します。また、モジュロ演算を自分で処理します。これはunsigned small : 4属性の値が0〜15で、16に到達する必要がある場合、前のビットは上書きされません:)
Matthieu M.

回答:


208

CPUが1バイトよりも小さいものに対処できないためです。


10
くそー、今それは厄介なサーです
Asm

31
実際には、4つのx86命令btbtsbtrbtc することができ、単一のビットに対応!
fredoverflow、2011年

11
btバイトオフセットをアドレス指定し、指定されたオフセットでビットをテストすると思いますが、アドレスをバイト単位で指定すると、ビットオフセットリテラルは少し冗長になります(しゃれを除く)。
user7116、2011年

2
@six:配列の先頭を1つのレジスタにロードしてから、相対「ビットオフセット」を2番目のレジスタにロードできます。ビットオフセットは「1バイト以内」に限定されず、任意の32ビット数にすることができます。
fredoverflow、2011年

4
はい、そうです。ビットフィールドはありますが、アドレス+ビット番号であるビットフィールドポインターを持つことができます。明らかに、そのようなポインタは、ビット数の追加のストレージ要件のため、void *に変換できません。
Maxim Egorushkin、2011年

32

ウィキペディアから:

歴史的に、1バイトはコンピューターでテキストの単一の文字をエンコードするために使用されるビット数でした。このため多くのコンピューターアーキテクチャーで基本的なアドレス指定可能な要素です。

バイトがあるので、基本的にアドレス可能なユニットは、その下のコンピュータ・アーキテクチャは、アドレスすることはできません。また、4ビットバイトをサポートするコンピューターは(おそらく)存在しないため、4ビットなどはありません。 bool

ただし、基本的なアドレス可能ユニットとして4ビットをアドレス指定できるこのようなアーキテクチャを設計できる場合bool、そのコンピュータでのみ4ビットのサイズになります。


4
「その場合、そのコンピュータでのみ、4ビットのintが存在することになります」-CHAR_BITが8未満になることは規格で禁止されているため、そうする必要はありません。アーキテクチャのアドレス可能なユニットが8ビット未満の場合、 C ++の実装では、基盤となるハードウェアのメモリモデルとは異なるメモリモデルを提示する必要があります。
Steve Jessop

@Steve:おっと...私はそれを見落としていた。削除されたintchar私のポストから。
Nawaz、2011年

1
4ビットにすることもできません。これは、アーキテクチャが独自のオペコードでアドレス指定できるものに関係なく、C ++でアドレス可能な最小単位boolだからです。少なくとも1の値が必要であり、隣接するオブジェクトはC ++で独自のアドレス持っている必要があるため、実装ではオブジェクトを大きくしてメモリを浪費する必要があります。そのため、ビットフィールドは特殊なケースとして存在します。構造体のビットフィールドメンバーは個別にアドレス指定できる必要はないため、aよりも小さくすることができます(ただし、構造体全体はまだ可能ではありません)。charsizeof(bool)boolchar
Steve Jessop、2011年

@スティーブジェソップ:それは興味深いようです。charC ++でアドレス可能な最小単位であると記載されている言語仕様からの参照を教えていただけますか?
Nawaz

3
最も近い特定のステートメントはおそらく3.9 / 4です:「T型のオブジェクトのオブジェクト表現は、T型のオブジェクトによって取り込まれたN個のunsigned charオブジェクトのシーケンスであり、Nはsizeof(T)に等しい」です。明らかsizeof(bool)に0.5 にすることはできません:-)私は実装が拡張としてサブバイトポインターを合法的に提供できると思いますが、通常の方法で割り当てられたboolのような「通常の」オブジェクトは標準が言うことをしなければなりません。
Steve Jessop、2011年

12

最も簡単な答えは、これは、CPUがメモリをビット単位ではなくバイト単位でアドレス指定し、ビット単位の操作が非常に遅いためです。

ただし、C ++でビットサイズの割り当てを使用することは可能です。ビットベクトル用のstd :: vector特殊化があり、ビットサイズのエントリを取る構造体もあります。


1
ビット単位の操作が遅いことに同意するかどうかはわかりません。ands、nots、xorsなどは非常に高速です。通常、遅いのはビット単位の演算の実装です。マシンレベルではかなり高速です。ブランチ...今は遅いです。
Hogan

3
より明確にするために、ブールのベクトルを作成し、それに24のブールを入れると、3バイト(3 * 8)しかかかりません。別のブール値を入れると、別のバイトがかかります。ただし、別のブール値をプッシュする場合、最後のバイトの「空き」ビットを使用するため、余分なバイトはかかりません
Pedro Loureiro

ええ、私もバイトワイズの操作が遅いのではないかと思います:)
ペドロ・ロウレイロ

ビットベクトルはビットサイズの割り当てを作成しません。バイトサイズの割り当てを作成します。単一ビットを割り当てることはできません。
John Dibling、2011年

1
ビットベクトルの単一ビットを読み取るには、シフト、およびシフトの3つの操作が必要です。書き込みは2つです。一方、個々のバイトは単一のバイトでアクセスできます。
sukru

7

昔は猛烈な吹雪の中を登り、両坂を登らなければならなかった昔、昼食は学校の後ろの森の中を追跡し、素手で殺すことができる動物だったのですが、コンピュータに利用できるメモリは今日。私が今まで使った最初のコンピュータには6KのRAMがありました。6メガバイトではなく、6ギガバイトではなく、6キロバイト。その環境では、できるだけ多くのブール値をintにパックすることは非常に理にかなっているので、定期的に操作を使用してブール値を取り出して配置しました。

今日、人々が1 GBのRAMしか持っていないと嘲笑し、200 GB未満のハードドライブを見つけることができる唯一の場所が骨董品店であるとき、ビットを詰めるのは面倒なことではありません。


フラグを扱う場合を除きます。何かに複数のオプションを設定するようなもの...例えば。00000001 + 00000100 =00000101。–
Armstrongest

@Atomix:私はこれをもうほとんどしません。2つのフラグが必要な場合は、2つのブールフィールドを作成します。以前はそのようなフラグをパックして「if flags&0x110!= 0 then」などと書くコードを書いていたが、これは不可解であり、最近では一般的に個別のフィールドを作成して「if fooFlag || barFlag "代わりに。何らかの理由でそのようなフラグをパッキングする方が良い場合の可能性を除外しませんが、以前のようにメモリを節約する必要がなくなりました。
Jay

2
実際には、計算を高速にしたい場合、つまりメモリに格納したその大量のデータに対してビットをパックすることは、かなりのトラブルに値します。ブール値のパッキングは、ストレージを小さくするためだけのものではありません。つまり、ブール値の入力配列を、アンパック時よりも8倍速く(帯域幅の観点から)読み取ることができます。これは、多くの場合非常に重要です。また、CPU自体での作業を高速化するpopc(population count)などのビット操作を使用できます。
einpoklum 2016年

2
本当に膨大な数のブール値は、DBMS、機械学習、科学的シミュレーション、およびその他の多くのことを行う場合、毎日使用するものです。そして、それらに取り組むということは、それらをメモリからキャッシュにコピーすることを意味します。100万のブール値は何もありません。
einpoklum 2016年

1
@PeterCordesはい、絶対に、論理的に「同じアイデア」であるブール値のセットがあり、ある意味でそれらを「配列」と自然に考える場合、そしてそれらをマスクまたはフィルタリングするか、それ以外の場合は、ビット単位の演算を実行してから、それらをバイトにパックするのが適切です。先に述べたように、これらの条件が適用されるアプリケーションに最後に取り組んだときのことを考えるのはつらいですが、良い例をいくつか挙げていただければ、他の人も思いつくかもしれません。
ジェイ

6

1ビットのブール値と4および2ビットの整数を使用できます。しかし、それはアーキテクチャを見るのに不自然な方法であるため、パフォーマンスが向上しない奇妙な命令セットになります。実際には、未使用のデータを再利用しようとするのではなく、バイトのより良い部分を「無駄にする」ことは理にかなっています。

私の経験では、いくつかのブール値を1バイトにパックするのが面倒な唯一のアプリはSQL Serverです。


5

ビットフィールドを使用して、サブサイズの整数を取得できます。

struct X
{
    int   val:4;   // 4 bit int.
};

これは通常、構造をハードウェアの予想ビットパターンにマッピングするために使用されます。

struct SomThing   // 1 byte value (on a system where 8 bits is a byte
{
    int   p1:4;   // 4 bit field
    int   p2:3;   // 3 bit field
    int   p3:1;   // 1 bit
};

5

バイトは言語でアドレス可能な最小単位だからです。

しかし、たとえば、それらの束がある場合、ブールを1ビット取ることができます。このような構造体で:

struct A
{
  bool a:1, b:1, c:1, d:1, e:1;
};

2

bool1バイトにすることができます-CPUのアドレス可能な最小サイズ、またはそれより大きくすることができます。パフォーマンスのためにのboolサイズである必要があるのは珍しいことではありませんint。特定の目的(ハードウェアシミュレーションなど)でNビットの型が必要な場合は、そのライブラリを見つけることができます(たとえば、GBLライブラリにはBitSet<N>クラスがあります)。bool(おそらく大きなコンテナーがある場合)のサイズが気になる場合は、自分でビットをパックするか、それを使用std::vector<bool>してそれを実行できます(コンテナーの要件を満たさないため、後者に注意してください)。


2

エミュレータレベルでこれを実装する方法について考えてください...

bool a[10] = {false};

bool &rbool = a[3];
bool *pbool = a + 3;

assert(pbool == &rbool);
rbool = true;
assert(*pbool);
*pbool = false;
assert(!rbool);

2

なぜなら、MIPSのような一部のCPUは4バイトワードを使用しますが、一般的に、CPUは1バイトを基本単位としてメモリを割り当てます。

ただし、特別な方法でvector処理さboolれ、vector<bool>ブールごとに1ビットが割り当てられます。


1
パフォーマンスは低下しますが、MIPS cpuでも個々のバイトにアクセスできると思います。
Paul Tomblin、2011年

@Paul:はい、そうですが、一般的には単語固有のlw/ swがはるかに広く使用されています。
Ryan Li

MIPSについては知りませんが、IA-64アーキテクチャーは64ビット境界でのみアクセスを許可します。
Gene Bushuyev、2011年

0

バイトは、コンピューターのデジタルデータストレージの小さな単位です。コンピューターでは、RAMに数百万バイトがあり、それらの誰もがアドレスを持っています。それがすべてのビットのアドレスを持っている場合、コンピュータはそれができるものより8倍少ないRAMを管理することができます。

詳細:ウィキペディア


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.