web-dev-qa-db-ja.com

unsigned intとsize_tの関係

私は、現代のCおよびC++コードがint/size_tの代わりにunsigned intをほとんどどこでも使用しているように見えることに気づいています - C文字列関数のパラメータからSTLまで。私はこの理由とそれがもたらす利点について興味があります。

466
Rob

size_t型はsizeof演算子(およびoffsetof演算子)の結果である符号なし整数型なので、システムが処理できる最大のオブジェクトのサイズを含むのに十分な大きさであることが保証されています(たとえば、静的配列)。 8Gb).

size_t型は、unsigned intよりも大きい、同じ、または小さい場合があります。最適化のために、コンパイラがそれを前提としている場合があります。

より正確な情報はC99標準、セクション7.17にあります。そのドラフトはインターネットで pdf 形式で、またはC11標準で入手可能です。 、セクション7.19、 pdfドラフト としても入手可能。

365
Remo.D

Classic C(Brian KernighanとDennis RitchieによってThe C Programming Language、1978年、Prentice-Hallによって説明されたCの初期の方言)はsize_tを提供しませんでした。 C標準化委員会は移植性の問題を排除するためにsize_tを導入しました

embedded.comで詳細に説明されています(非常に良い例付き)

92
azeemarif

つまり、size_tは負になることはなく、ターゲットプラットフォーム上で可能な最大のオブジェクトのサイズを表すのに十分な大きさで、大きすぎない符号付き整数型であることがtypedefされているため、パフォーマンスが最大になります。

サイズが負になることは絶対にありません。実際、size_tは符号なし型です。また、size_tは符号なしであるため、符号付き整数の他のすべてのビットと同様に、符号ビットを使用して大きさを表すことができるため、対応する符号付き型の約2倍の大きさの数値を格納できます。もう1つビットを取得すると、表現できる数値の範囲に約2の係数を掛けます。

それで、あなたは尋ねます、なぜunsigned intを使わないのですか?十分に大きい数を保持することができないかもしれません。 unsigned intが32ビットの実装では、それが表すことができる最大数は4294967295です。 IP16L32などの一部のプロセッサは、4294967295バイトより大きいオブジェクトをコピーできます。

それで、あなたは尋ねます、なぜunsigned long intを使わないのですか?一部のプラットフォームではパフォーマンスが低下します。標準Cでは、longが少なくとも32ビットを占めることを要求しています。 IP16L32プラットフォームは、それぞれ32ビット長を1組の16ビットワードとして実装します。これらのプラットフォーム上のほとんどすべての32ビット演算子は、2つの16ビットチャンクで32ビットを処理するため、2つ以上の命令を必要とします。たとえば、32ビット長を移動するには、通常、2つの機械命令が必要です。1つは各16ビットチャンクを移動するための命令です。

size_tを使用すると、このパフォーマンスの低下を回避できます。 この素晴らしい記事 によると、Type size_tは、符号なし整数型のエイリアスで、通常はunsigned intまたはunsigned longですが、おそらくunsigned long longでさえあるtypedefです。各Standard C実装は、符号なし整数を選択することになっています。ターゲットプラットフォーム上で可能な最大のオブジェクトのサイズを表すのに十分な大きさ - ただし必要以上の大きさではない - 」

68
Rose Perrone

Size_t型は、sizeof演算子によって返される型です。ホストマシンでサポートされている任意のメモリ範囲のサイズをバイト単位で表現できる符号なし整数です。 ptrdiff_tは、sizeof(ptrdiff_t)とsizeof(size_t)が等しくなるような符号付き整数値であるという点で(通常)ptrdiff_tに関連しています。

Cコードを書くときは、常にメモリ範囲を扱うときはいつもsize_tを使うべきです。

一方、int型は基本的に、ホストマシンが整数演算を最も効率的に実行するために使用できる(符号付き)整数値のサイズとして定義されています。たとえば、多くの古いPCタイプのコンピュータでは、sizeof(size_t)の値は4(バイト)になりますが、sizeof(int)の値は2(バイト)になります。 CPUは最大4 GiBの(論理)メモリ空間を処理できますが、16ビット演算は32ビット演算より高速です。

実際の精度はコンパイラオプションとマシンアーキテクチャの両方に強く依存するため、int型は効率を気にする場合にのみ使用してください。特にC規格では、次の不変式を指定しています。sizeof(char)<= sizeof(short)<= sizeof(int)<= sizeof(long)これらのプリミティブ型.

注:これはJavaの場合と同じではありません(実際には、 'char'、 'byte'、 'short'、 'int'、および 'long'の各型のビット精度が指定されています)。

48
Kevin S.

Size_t型は、可能性のあるオブジェクトのサイズを格納するのに十分な大きさでなければなりません。 unsigned intはその条件を満たす必要はありません。

例えば64ビットシステムではintとunsigned intは32ビット幅かもしれませんが、size_tは4Gより大きな数を格納するのに十分な大きさでなければなりません。

23
Maciej Hehl

Glibcマニュアル0.02からのこの抜粋は、トピックを調査するときにも関連があります。

Size_t型およびリリース2.4より前のGCCのバージョンには潜在的な問題があります。 ANSI Cは、size_tが常に符号なしの型であることを要求します。既存のシステムのヘッダファイルとの互換性のために、GCCはstddef.h' to be whatever type the system'ssys/types.hでsize_tを定義します。 `sys/types.h 'でsize_tを定義しているほとんどのUnixシステムは、それを符号付き型として定義しています。ライブラリ内の一部のコードは、size_tが符号なしタイプであることに依存しており、それが署名されていると正しく機能しません。

Size_tが符号なしであることを期待するGNU Cライブラリコードは正しいです。符号付き型としてのsize_tの定義が正しくありません。バージョン2.4では、GCCは常にsize_tを符号なしの型として、そしてfixincludes' script will massage the system'ssys/types.h 'をそれと矛盾しないように定義する予定です。

それまでの間、GNU Cライブラリをコンパイルするときに、GCCにsize_tに符号なし型を使用するように明示的に指示することで、この問題を回避します。 `configure 'はGCCがsize_tのためにどのタイプを使用するかを自動的に検出し、必要ならばそれを上書きするように調整します。

3
Graeme Burke

私のコンパイラが32ビットに設定されている場合、size_tunsigned intのtypedef以外の何ものでもありません。私のコンパイラが64ビットに設定されている場合、size_tunsigned long longのtypedef以外の何ものでもありません。

1
Zebrafish