C/C++ で通常使用できるすべてのデータ型のうち、一部のデータ型が OS またはコンパイラに依存しているのはなぜですか?
これには論理的な理由がありますか、それとも単に設計によるものですか?
C/C++ で通常使用できるすべてのデータ型のうち、一部のデータ型が OS またはコンパイラに依存しているのはなぜですか?
これには論理的な理由がありますか、それとも単に設計によるものですか?
はい。C/C++ はさまざまなマシン アーキテクチャで実行されるためです。
したがってint
、マシンの「自然なサイズ」として定義されます。これにより、コンパイラはそのマシンで適切に実行されるコードを生成できます。
最新のマシンでは、通常 32 ビットまたは 64 ビットです。古いマシンでは、16 ビットでした。一部のマシン (調べることができます) では、24 ビットまたは 36 ビットでした。
C 標準は、これらの型の定義に非常に注意を払っています。他のことは実装に任せますが、いくつかのこと(「long
より小さくすることはできません」など)が必要です。int
int
この点に関しては特別なことではありません。すべての整数データ型はコンパイラに依存します。各タイプには最小範囲があり、タイプにはサイズが減少しない順序があります: char
-> short
-> int
-> long
-> long long
. 適合する実装では、それらすべてを 64 ビット幅にすることができます。
タイプは、int
使用しているアーキテクチャの自然なサイズであると想定されています。そのため、32 ビット マシンでint
は通常 32 ビットです。64 ビットでint
は、通常は 64 ビットです。(64 ビット マシン上の 32 ビット OS は、おそらく 32 ビットになりますint
。)
その理由は効率です。多くの場合、表現可能な最大量は実際には重要ではなく、最も効率的な型を使用したいだけです。最も一般的な例はループです。
for(int i=0; i< NUM_ITER; ++i) {
// ...
}
ほとんどのループでは、通常、反復回数はそれほど多くありません。しかし、255 回以上ループする必要がないことがわかっていても、たとえば、unsigned char
ループ カウンターを使用すると、実際にはレジスターの使用などの点で効率が低下する可能性があります。
編集:これは別の例です。ワード サイズが 4 バイトで、次のような関数があるとします。
void foo() {
static char x;
static char y;
// ...
}
それを単純にコンパイルすると、変数x
がたとえば0x0F00
. 次に、変数は1バイトしか必要ないためy
、単純なコンパイルによってアドレスに配置されます。しかし、多くのアーキテクチャでは、メモリ アクセスは 4 バイト アラインされたアドレスに対して最適化されているため、アクセスは への/からの 4 バイト アクセスとして実装され、それらのバイトのうち 3 バイトが破棄される場合があります。これは帯域幅の消費という点では明らかに無駄ですが、より大きな問題は、4 バイト ワードでバイトをパック/アンパックするために行わなければならない余分な処理です。0x0F01
x
y
0x0F00
OTOH、 1 バイトより大きくx
てy
も問題ない場合 (つまり、アルゴリズムの一部として変数のオーバーフローに依存しない場合)、それらを として宣言する方がよいでしょうint
。値が 256 未満であっても、毎回 4 バイトにアクセスすることになりますが、これは無駄ですが、前のケースほどではありません。ただし、変数をパックまたはアンパックする必要がなくなったため、オーバーヘッドが少しなくなりました。
x
要点は、単純に andy
を as として宣言すればint
、32 ビット アーキテクチャと 64 ビット アーキテクチャのアライメントについて心配する必要がないということです。コンパイラはどちらの方法でも正しいことを行います。