私が理解しているように、C仕様では、型int
は、少なくとも16ビットを含むターゲットプラットフォームで最も効率的な型であると想定されています。
C99のint_fast16_t
の定義もそうではありませんか。
他のint_fastXX_t
が必要なため、一貫性を保つために配置したのでしょうか?
更新
以下の議論を要約すると:
例: x86-64上のMSVCには、64ビットシステムであっても32ビットintがあります。 intは常に正確に32ビットであると想定している人が多すぎるため、MSはこれを選択しました。ただし、x86-64で64ビット値の方が高速である場合、int_fast32_tが64ビット数になる可能性があります。 (私は実際にはそうではないと思いますが、それは要点を示すだけです)
int_fast16_t
は、16ビット以上のサイズで最速のintであることが保証されています。 int
は、次の場合を除いて、そのサイズを保証しません。
sizeof(char) = 1 and sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long).
そして、それは-32767から+32767の範囲を保持できます。
(7.20.1.3p2) "typedef名
int_fastN_t
は、少なくとも[〜#〜] n [〜#〜]の幅を持つ最速の符号付き整数型を示します。 typedef名uint_fastN_t
は、少なくとも幅が[〜#〜] n [〜#〜]の最も高速な符号なし整数型を示します。 "
int
は、速度/サイズが「最も効率的なタイプ」ですが、C仕様では指定されていません。 16ビット以上である必要があります。
int_fast16_t
は少なくとも 16ビット整数の範囲で速度が最も効率的なタイプです。
例:特定のプラットフォームでは、速度だけでなく、さまざまな理由でint
を32ビットにする必要があると判断した可能性があります。同じシステムが、16ビット整数の場合、異なるタイプが最も高速であると判断する場合があります。
例:64ビットマシンで、int
を64ビットとして使用すると予想される場合、コンパイラーは互換性のために32ビットint
コンパイルのモードを使用できます。このモードでは、int_fast16_t
は本来64ビットである可能性があります。これはネイティブで最速の幅であるため、アライメントの問題などを回避するためです。
私が理解しているように、C仕様では、型
int
は、少なくとも16ビットを含むターゲットプラットフォームで最も効率的な型であると想定されています。
標準がint
について実際に言っているのは次のとおりです:( N1570ドラフト 、セクション6.2.5、パラグラフ5):
「プレーン」
int
オブジェクトは、実行環境のアーキテクチャによって提案された自然なサイズです(範囲INT_MIN
〜INT_MAX
定義どおりヘッダー内<limits.h>
)。
INT_MIN
およびINT_MAX
への参照は、おそらく少し誤解を招く可能性があります。これらの値は、タイプint
の特性に基づいて選択され、逆ではありません。
また、「the自然なサイズ」というフレーズも少し誤解を招きやすいものです。ターゲットアーキテクチャによっては、整数型の「自然な」サイズが1つだけではない場合があります。
他の場所では、規格は、INT_MIN
は最大-32767
である必要があり、INT_MAX
は少なくとも+32767
である必要があるとしています。これは、int
が少なくとも16であることを意味しますビット。
これは、規格がint_fast16_t
(7.20.1.3)について述べていることです。
次の各型は、少なくとも指定された幅を持つすべての整数型の中で通常最も高速に動作する整数型を指定します。
脚注付き:
指定されたタイプがすべての目的で最速であるとは限りません。あるタイプを別のタイプから選択する明確な根拠がない場合は、符号付きと幅の要件を満たす整数タイプを選択するだけです。
int
とint_fast16_t
の要件は似ていますが、同一ではありません-どちらも同様にあいまいです。
実際には、int
のサイズは、「自然なサイズ」以外の基準に基づいて選択されることが多く、またはその句は便宜上解釈されます。多くの場合、新しいアーキテクチャのint
のサイズは、既存のアーキテクチャのサイズと一致するように選択され、コードの移植の難しさを最小限に抑えます。そして、int
を32ビットより広くしないようにするかなり強い動機があるので、char
、short
、およびint
は8のサイズをカバーできます。 、16、および32ビット。 64ビットシステム、特にx86-64では、「自然な」サイズはおそらく64ビットですが、ほとんどのCコンパイラはint
を64ではなく32ビットにします(一部のコンパイラはlong
32ビット)。
int_fast16_t
の基礎となる型の選択は、それを使用するすべてのコードが高速の16ビット符号付き整数型を明示的に要求しているため、このような考慮事項への依存度が低いと思います。既存のコードの多くは、標準で保証されている以上のint
の特性を前提としているため、コンパイラーの開発者は、コンパイラーを使用する場合にそのようなコードに対応する必要があります。
C99の根拠7.8
整数型のフォーマット変換<inttypes.h>
(標準に付属するドキュメント)から、次の点を強調します。
C89は、言語が4つの符号付きおよび符号なし整数データ型、
char
、short
、int
およびlong
をサポートする必要があることを指定していますが、それらの要件はほとんどありません。サイズそれ以外はint
とshort
は少なくとも16ビットであり、long
はint
と同じ長さで32以上であるビット。 16ビットシステムの場合、ほとんどの実装では、8、16、16、32ビットをそれぞれchar
、short
、int
、long
に割り当てます。 32ビットシステムでは、8、16、32、32ビットをこれらのタイプに割り当てるのが一般的です。int
サイズのこの違いは、システムから別のシステムに移行して整数型に異なるサイズを割り当てるユーザーにいくつかの問題を引き起こす可能性があります。これは、Standard Cの整数昇格規則が予期せずサイレント変更を生成する可能性があるためです。 64ビットシステムの導入に伴い、拡張整数型を定義する必要性が高まりました。
<inttypes.h>
の目的は、整数型のセットを提供することですその定義はマシン間で一貫しており、オペレーティングシステムや他の実装の特異性とは無関係です。typedef
を介して、さまざまなサイズの整数型を定義します。実装は、それらがサポートする標準C整数型または拡張として、自由にtypedef
できます。このヘッダーを一貫して使用すると、プラットフォーム間でのユーザーのプログラムの移植性が大幅に向上します。
int
とint_fast16_t
の主な違いは、後者にはこれらの「実装の特異性」がない可能性が高いことです。あなたはそれを次のようなものと考えるかもしれません:
int
サイズの現在のOS /実装の「政治」は気にしません。少なくとも16ビットの最速の符号付き整数型を教えてください。
違いは、fastタイプは、よりも広い効率/最適化のための対応(fastなし)。しかし、C標準は、それらが実際に高速であることを決して保証しません。
C11、7.20.1.3最速の最小幅整数型
1次の各型は、少なくとも指定された幅を持つすべての整数型の中で動作するのに通常最も高速な整数型を示します262)。
2 typedef名int_fastN_tは、幅がN以上の最速の符号付き整数型を示します。typedef名uint_fastN_tは、幅がN以上の最速の符号なし整数型を示します。
262)指定されたタイプがすべての目的で最速であるとは限りません。あるタイプを別のタイプから選択する明確な根拠がない場合は、符号付きと幅の要件を満たす整数タイプを選択するだけです。
もう1つの違いは、fastおよびleast型が必須型であるのに対し、他の正確な型は幅のタイプはオプションです:
3次のタイプが必要です。
一部のプラットフォームでは、16ビット値を使用すると、32ビット値を使用する場合よりもはるか遅くなる可能性があります[例: 8ビットまたは16ビットのストアでは、32ビットのロードを実行し、ロードされた値を変更して、結果を書き戻す必要があります]。 32ビット値の2倍の数の16ビット値をキャッシュに収めることができたとしても(32ビットシステムでは、16ビット値が32ビット値より速い通常の状況)、すべての書き込みが必要データ構造が書き込まれたよりもはるかに頻繁に読み取られない限り、読み取りの前に速度の利点はありません。このようなプラットフォームでは、int_fast16_t
のような型は32ビットになる可能性があります。
そうは言っても、標準では残念ながらコンパイラーにとって最も役立つセマンティクスを許可していません。これは、アドレスが任意に16ビットタイプ以上として動作しないint_fast16_t
タイプの変数を許可することです。タイプは、何が便利かによって異なります。たとえば、次のメソッドについて考えます。
int32_t blah(int32_t x)
{
int_fast16_t y = x;
return y;
}
多くのプラットフォームでは、メモリに格納されている16ビット整数は、レジスタに格納されている整数と同じように操作できますが、レジスタで16ビット演算を実行するための命令はありません。メモリに格納されているint_fast16_t
変数が-32768〜+32767しか保持できない場合、同じ制限がレジスタに格納されているint_fast16_t
変数に適用されます。サイズが大きすぎる値を保持するには小さすぎる符号付き整数型に強制変換するのは実装定義の動作であるため、上記のコードでは、返す前にx
の下位16ビットに符号拡張する命令を追加せざるを得ません。規格がそのような型を許可している場合、柔軟な「少なくとも16ビットだが便利な場合はもっと多い」型は、そのような命令の必要性をなくすことができます。
2つのタイプの違いの例:8ビット、16ビット、32ビット、64ビットの演算が同等に高速であるアーキテクチャがあるとします。 (i386が近づきます。)次に、実装者はLLP64モデルを使用するか、さらにはプログラマがILP64、LP64、LLP64のいずれかを選択できるようにします。 sizeof(int) <= sizeof(void*) <= sizeof(long)
。 64ビットの実装は、これらの前提の少なくとも1つに違反する必要があります。
その場合、int
はおそらく32ビット幅になります。これは、他のシステムからのコードを最小限に抑えるためですが、uint_fast16_t
は依然として16ビット幅で、スペースを節約できます。