符号なし整数とsize_t


492

最近のCおよびC ++コードは、C文字列関数のパラメーターからSTLまで、ほとんどどこでも/のsize_t代わりに使用しているようです。この理由とそれがもたらす利点について知りたいです。intunsigned int

回答:


388

size_tタイプの結果である符号なし整数型であり、sizeofオペレータ(及びoffsetofあなたのシステムが処理できる最大のオブジェクト(たとえば、8GBのの静的配列)のサイズを格納するための十分な大きさであることが保証されるように、オペレータ)。

size_tタイプは、より、より大きな等しい、または小さくてもよくunsigned int、そして、あなたのコンパイラが最適化のためにそれについての仮定を行うことがあります。

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


50
いいえ。大きな(巨大ではない)メモリモデルを備えたx86-16について考えてみます。ポインタは遠く(32ビット)ですが、個々のオブジェクトは64kに制限されています(したがって、size_tは16ビットにすることができます)。
dan04 2010年

8
「最大のオブジェクトのサイズ」は言い回しではありませんが、完全に正しいです。オブジェクトのシックスは、アドレス空間よりもはるかに制限されている場合があります。
gnasher729 2014

3
「あなたのコンパイラはそれについて仮定するかもしれません」:コンパイラが表現できる値の正確な範囲を知っていることを望みますsize_t!そうでない場合、誰がしますか?
Marc van Leeuwen

4
@Marc:コンパイラがその知識で何か実行できるかもしれないという点が多かったと思います。

8
このますます人気が高まっているタイプで、ヘッダーファイルを含める必要がないことを願っています。
user2023370 2016

98

クラシックC(ブライアンカーニハンとデニスリッチーがThe C Programming Language、Prentice-Hall、1978年に記述したCの初期の方言)は提供しませんでしたsize_t。導入されたC規格委員会size_t移植性の問題を排除するためにされた

embedded.comで詳細に説明されている(非常に良い例を使用)


6
size_tとptrdiff_tの両方を説明する優れた記事:viva64.com/en/a/0050
Ihor Kaharlichenko

73

要するに、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ビットの長さを16ビットワードのペアとして実装します。これらのプラットフォームのほとんどすべての32ビットオペレーターは、32ビットを2つの16ビットチャンクで処理するため、2つ以上の命令が必要です。たとえば、32ビットのlongを移動するには、通常2つのマシン命令が必要です。1つは各16ビットのチャンクを移動するためのものです。

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


1
長い間これについてコメントして申し訳ありませんが、私はunsigned intが保持できる最大数を確認する必要がありました-おそらくあなたの用語を誤解しているかもしれませんが、私はunsigned intが保持できる最大数は4294967295、65356であると思いました符号なしshortの最大値。
ミッチ

unsigned intが32ビットを使用している場合、はい、保持できる最大の数は2 ^ 32-1で、4294967295(0xffffffff)です。別の質問がありますか?
ローズペローネ

3
@ミッチ:缶で表すことができる最大の値で、unsigned intシステムによって異なります。それは少なくとも 65536である必要がありますが、それは一般的で4294967295あり18446744073709551615、一部のシステムでは(2 ** 64-1)になる可能性があります。
キース・トンプソン

1
16ビットのunsigned intに含めることができる最大値は65535であり、65536ではありません。65536は、16ビットのunsigned intの0と同じですが、重要ではありません。
Sie Raybould、

1
@ gnasher729:C ++標準について確信がありますか?しばらく検索してみたところ、整数範囲(を除くunsigned char)に関する絶対的な保証がすべて削除されたように見えます。標準には、文字列「65535」または「65536」がどこにも含まれていないようです。「+ 32767」は、で表現可能な最大の整数としてノートでのみ発生します(1.9:9)intINT_MAXそれより小さくても保証はありません!
Marc van Leeuwen

51

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(バイト)です。16ビット演算は32ビット演算よりも高速でしたが、CPUは最大4 GiBの(論理)メモリ空間を処理できました。

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

注:これはJavaの場合とは異なります(実際には、「char」、「byte」、「short」、「int」、および「long」の各タイプのビット精度を指定します)。


intの事実上の定義は、16台のマシンでは16ビット、それ以上のマシンでは32ビットであるということです。intが32ビット幅であると想定したコードが多すぎるため、これを変更するため、特定のものが必要な場合は常にsize_tまたは{、u} int {8,16,32,64} _tを使用する必要があります- -予防策として、整数型ではなく、常にこれらを使用する必要があります。
2014

3
「これは、ホストマシンでサポートされているメモリ範囲のサイズをバイト単位で表現できる符号なし整数です。」-> No. size_tは、任意の単一オブジェクト(例:数値、配列、構造)のサイズを表すことができます。メモリ全体の範囲を超えている可能性がありますsize_t
chux-モニカを2015年

「Cコードを作成するときは、メモリ範囲を処理するときは常にsize_tを使用する必要があります。」-これは、すべての配列のすべてのインデックスsize_tがそうであることを意味します-あなたがそれを意味しないことを願っています。ほとんどの場合、アドレス空間のカーディナリティ+移植性が問題になる配列については扱いません。これらの場合、あなたは取るでしょうsize_t。他のすべての場合では、(符号付き)整数からインデックスを取り出します。符号なしの予期せぬアンダーフロー動作が原因で発生する混乱(警告なし)は、他のケースで発生する可能性のある移植性の問題よりも一般的であり、悪いためです。
johannes_lalala

23

タイプsize_tは、可能なオブジェクトのサイズを格納するのに十分な大きさでなければなりません。符号なし整数は、その条件を満たす必要はありません。

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


38
「オブジェクト」は、標準で使用される言語です。
R .. GitHub ICE HELPING ICEの停止

2
size_tsizeof(X)が4Gより大きい値を生成するようなコンパイラーがタイプXを受け入れることができる場合のみ、私はその大きさである必要があると思います。ほとんどのコンパイラは、たとえばを拒否しtypedef unsigned char foo[1000000000000LL][1000000000000LL]foo[65536][65536];実装で定義された制限を超えた場合は合法的に拒否される可能性さえあります。
スーパーキャット2014年

1
@MattJoiner:文言は結構です。「オブジェクト」はまったく曖昧ではなく、「ストレージの領域」を意味するように定義されています。
オービットのライトネスレース2015年

4

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

リリース2.4より前のGCCのsize_tタイプとバージョンに潜在的な問題があります。ANSI Cでは、size_tは常に符号なしの型である必要があります。既存のシステムのヘッダーファイルとの互換性のために、GCCはsize_tをstddef.h' to be whatever type the system's sys / types.hで定義し、それがそうであることを定義します。`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ライブラリをコンパイルするときに、size_tに符号なしの型を使用するようにGCCに明示的に指示することで、この問題を回避します。`configure 'は、GCCがsize_tに使用するタイプを自動的に検出し、必要に応じてそれを上書きします。


2

コンパイラが32ビットに設定されているsize_t場合、のtypedefにすぎませんunsigned int。コンパイラが64ビットに設定されている場合size_tは、のtypedefにすぎませんunsigned long long


1
unsigned long一部のOSでは両方の場合と同様に定義できます。
StaceyGirl 2018

-4

size_tは、ポインターのサイズです。

したがって、32ビットまたは一般的なILP32(整数、ロング、ポインター)モデルでは、size_tは32ビットです。64ビットまたは一般的なLP64(long、ポインター)モデルでは、size_tは64ビットです(整数は32ビットのままです)。

他のモデルもありますが、これらはg ++が使用するものです(少なくともデフォルトでは)。


15
size_t通常は同じですが、ポインタと同じサイズである必要はありません。ポインタは、メモリ内の任意の場所を指すことができる必要があります。size_t最大の単一オブジェクトのサイズを表すのに十分な大きさでなければなりません。
キース・トンプソン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.