Code Review のレビューで、今日興味深い点に出会いました。 @Veedracは この答え で推奨されています。可変サイズタイプ(int
やlong
など)は、uint64_t
やuint32_t
などの固定サイズタイプに置き換えられます。その回答のコメントからの引用:
Intとlongのサイズ(およびそれらが保持できる値)はプラットフォームに依存します。一方、int32_tは常に32ビット長です。 intを使用するということは、コードがプラットフォームごとに異なる動作をすることを意味します。
標準が一般的な型を修正しない理由は、@ supercatによって部分的に説明されています here 。 Cは、当時システムプログラミングに通常使用されていたAssemblyとは異なり、アーキテクチャ間で移植できるように作成されています。
デザインの意図は、もともとint以外の各タイプがさまざまなサイズの数を処理できる最小のものであり、intが+/- 32767を処理できる最も実用的な「汎用」サイズであることだと思います。
私については、常にint
を使用しており、代替案についてはあまり心配していません。私はいつもそれが最高のパフォーマンスとストーリーの終わりの最もタイプだと思っていました。固定幅が便利だと私が思った唯一の場所は、ストレージまたはネットワーク経由の転送のためにデータをエンコードするときです。他の人が書いたコードで固定幅型を見たことはほとんどありません。
70年代に留まっているのですか、それとも実際にC99の時代以降にint
を使用する根拠はありますか?
uint32_t
のような型は、プログラマがint
のサイズを気にする必要がないという一般的で危険な神話があります。標準委員会がマシンに依存しないセマンティクスで整数を宣言する手段を定義することは有益ですが、uint32_t
のような符号なしの型はセマンティクスが緩すぎて、どちらもクリーンな方法でコードを記述できませんそしてポータブル;さらに、int32
のような符号付きの型は、多くのアプリケーションの方法で不必要に厳密に定義されているセマンティクスを持っているため、他の方法では有用な最適化ができなくなります。
たとえば、次のことを考慮してください。
uint32_t upow(uint32_t n, uint32_t exponent)
{
while(exponent--)
n*=n;
return n;
}
int32_t spow(int32_t n, uint32_t exponent)
{
while(exponent--)
n*=n;
return n;
}
int
が4294967295を保持できないか、18446744065119617025を保持できるマシンでは、最初の関数はn
とexponent
のすべての値に対して定義され、その動作には影響しませんint
のサイズさらに、規格では、int
のサイズが異なるマシンで異なる動作を生成する必要はありませんが、n
およびexponent
の値によっては、未定義の動作が呼び出される場合があります。 4294967295はint
として表現できますが、18446744065119617025は表現できないマシンでは。
2番目の関数は、n
が4611686014132420609を保持できないマシンで、exponent
およびint
のいくつかの値に対して未定義の動作を生成しますが、n
およびexponent
が可能なすべてのマシン(int32_t
の仕様は、int
より小さいマシンでの2の補数の折り返し動作を意味します)。
歴史的に、標準はコンパイラがint
のupow
オーバーフローで何をすべきかについて何も言わなかったとしても、int
が十分に大きくなかったかのように、コンパイラは一貫して同じ動作をもたらしましたオーバーフローする。残念ながら、一部の新しいコンパイラは、標準で規定されていない動作を排除することによってプログラムを「最適化」しようとする場合があります。
バッファーサイズ、配列インデックス、WindowsのlParam
などのポインター(つまり、アドレス可能なメモリの量)に密接に関連する値の場合、アーキテクチャに依存するサイズの整数型を使用することは理にかなっています。したがって、variable-sized型は引き続き役立ちます。 typedefがsize_t
、ptrdiff_t
、intptr_t
などになっているのはこのためです。組み込みのC整数型では必要ないため、それらはtypedefになりますhaveポインタサイズである。
したがって、問題は、char
、short
、int
、long
、およびlong long
がまだ有用かどうかということです。
IME、CおよびC++プログラムがほとんどの場合にint
を使用することは依然として一般的です。そして、ほとんどの場合(つまり、数値が±32 767の範囲にあり、厳密なパフォーマンス要件がない場合)、これは問題なく機能します。
しかし、17〜32ビットの範囲の数値(大都市の人口など)を処理する必要がある場合はどうでしょうか。 int
を使用することもできますが、これはプラットフォームの依存関係をハードコーディングすることになります。標準に厳密に準拠したい場合は、少なくとも32ビットであることが保証されているlong
を使用できます。
問題は、C標準が整数型に対して最大サイズを指定していないことです。 long
が64ビットであり、メモリ使用量が2倍になる実装があります。そして、これらのlong
sがたまたま数百万のアイテムを持つ配列の要素である場合、狂ったようにメモリを破壊するでしょう。
したがって、プログラムをクロスプラットフォームでメモリ効率の高いものにしたい場合、int
もlong
もここで使用するのに適したタイプではありません。 int_least32_t
と入力します。
long
を提供し、int
の切り捨ての問題を回避しますint
を提供し、64ビットのlong
のメモリの無駄を回避します。int
を提供しますOTOH、あなたがしないでください巨大な数または巨大な配列が必要であると仮定しますが、速度が必要です。また、int
はすべてのプラットフォームで十分な大きさである可能性がありますが、必ずしも最速のタイプであるとは限りません。64ビットシステムには通常、32ビットint
がまだあります。しかし、int
、long
、int_fast16_t
のいずれであっても、long long
を使用して「最速」のタイプを取得できます。
したがって、<stdint.h>
の型には実用的な使用例があります。標準の整数型はmean何もしません。特にlong
は、32ビットまたは64ビットであり、コンパイラー作成者の気まぐれに応じて、ポインターを保持するのに十分な大きさである場合とそうでない場合があります。