今日のクロスプラットフォームC++(またはC)の世界では、 have :
Data model | short | int | long | long long | pointers/size_t | Sample operating systems
...
LLP64/IL32P64 16 32 32 64 64 Microsoft Windows (x86-64 and IA-64)
LP64/I32LP64 16 32 64 64 64 Most Unix and Unix-like systems, e.g. Solaris, Linux, BSD, and OS X; z/OS
...
これが今日意味することは、「一般的な」(符号付き)整数の場合、int
で十分であり、C++アプリケーションコードを作成するときにデフォルトの整数型として引き続き使用できる可能性があるということです。また、現在の実用的な目的のために-プラットフォーム間で一貫したサイズになります。
ユースケースに少なくとも64ビットが必要な場合、今日はlong long
、ただし ビット数を指定するタイプ または__int64
typeの方がわかりやすいかもしれません。
これにより、long
が途中に残り、アプリケーションコードからlong
の使用を完全に禁止することを検討しています。
これは理にかなっていますか、またはクロスプラットフォームを実行する必要がある最新のC++(またはC)コードでlong
を使用するケースがあります? (プラットフォームはデスクトップ、モバイルデバイスですが、マイクロコントローラー、DSPなどではありません)
おそらく興味深い背景リンク:
long
は少なくとも32ビットであることが保証されていますか? (これは以下のコメントの議論に対応します。 Answer 。)今日long
を使用する唯一の理由は、それを使用する外部インターフェイスを呼び出すか実装するときです。
あなたの投稿で言っているように、shortとintは今日のすべての主要なデスクトップ/サーバー/モバイルプラットフォームでかなり安定した特性を持っています。ですから、一般的にそれらを避ける理由はほとんどありません。
一方、long
はごちゃごちゃです。すべての32ビットシステムで、次の特徴があることを認識しています。
これらの特性の1つ以上に基づいて大量のコードが記述されました。ただし、64ビットへの移行により、それらすべてを保持することはできませんでした。 Unixライクなプラットフォームは、特性1を犠牲にして特性2と3を維持するLP64を採用しました。Win64は、特性2と3を犠牲にして特性1を維持するLLP64を採用しました。その結果、これらの特性のいずれにも依存できなくなりました。 IMOはlong
を使用する理由をほとんど残していません。
サイズが正確に32ビットの型が必要な場合は、int32_t
を使用する必要があります。
ポインタと同じサイズの型が必要な場合は、intptr_t
(またはより適切なuintptr_t
)を使用する必要があります。
単一のレジスター/命令で処理できる最大の項目であるタイプが必要な場合、残念ながら、標準では提供されていないと思います。 size_t
はほとんどの一般的なプラットフォームで適切ですが、 x32 にはありません。
追伸.
「高速」または「最小」タイプは気にしません。 「最小」タイプは、移植性を気にしてCHAR_BIT != 8
であるアーキテクチャを本当に不明瞭にする場合にのみ重要です。実際の「高速」タイプのサイズはかなり任意のようです。 Linuxはそれらを少なくともポインタと同じサイズにするようです。これは、x86-64やarm64などの高速32ビットサポートを備えた64ビットプラットフォームでは愚かです。 IIRC iOSはそれらを可能な限り小さくします。他のシステムが何をしているのかわかりません。
P.P.S
unsigned long
(プレーンlong
ではない)を使用する理由の1つは、モジュロ動作が保証されているためです。残念ながら、Cのめちゃくちゃなプロモーションルールにより、int
より小さい符号なしの型はモジュロ動作をしません。
今日のすべての主要なプラットフォームでuint32_t
はintと同じかそれより大きいため、モジュロ動作をします。ただし、歴史的に存在し、int
が64ビットであり、したがってuint32_t
がモジュロ動作を行わない将来のプラットフォームにも理論的には存在する可能性があります。
個人的には、式の最初に「1u *」または「0u +」を使用してモジュロ動作を強制するという習慣を身に付ける方が良いと思います。これは、あらゆるサイズの符号なしの型で機能するためです。
あなたの質問で述べたように、現代のソフトウェアはすべて、インターネット上のプラットフォームとシステムの間の相互運用に関するものです。 CおよびC++標準では、特定のサイズではなく整数型のサイズの範囲が指定されます(JavaおよびC#などの言語とは対照的)。
異なるプラットフォームでコンパイルされたソフトウェアが同じ方法で同じデータで動作するようにするおよび他のソフトウェアが同じサイズを使用してソフトウェアとやり取りできるようにするには、固定サイズを使用する必要があります-サイズの整数。
入る - <cstdint>
これは正確にそれを提供し、すべてのコンパイラおよび標準ライブラリプラットフォームが提供する必要がある標準ヘッダーです。注:このヘッダーはC++ 11の時点でのみ必要でしたが、いずれにせよ、多くの古いライブラリ実装で提供されていました。
64ビットの符号なし整数が必要ですか?使用する uint64_t
。符号付き32ビット整数?使用する int32_t
。ヘッダーのタイプはオプションですが、最新のプラットフォームはそのヘッダーで定義されているすべてのタイプをサポートする必要があります。
他のシステムとの通信に使用されるデータ構造などでは、特定のビット幅が必要になる場合があります。それ以外の場合はそうではありません。それほど厳密ではない状況では、<cstdint>
は最小幅のタイプを提供します。
leastバリアントがあります:int_leastXX_t
は、最小XXビットの整数型になります。 XXビットを提供する最小のタイプを使用しますが、タイプは指定されたビット数より大きくすることができます。実際には、これらは通常、正確なビット数を与える上記のタイプと同じです。
fastバリアントもあります:int_fastXX_t
は少なくともXXビットですが、特定のプラットフォームで高速に実行されるタイプを使用する必要があります。この文脈での「高速」の定義は規定されていません。ただし、実際には、これは通常、CPUのレジスタサイズよりも小さい型がCPUのレジスタサイズの型にエイリアスになる可能性があることを意味します。たとえば、Visual C++ 2015のヘッダーでは、int_fast16_t
は32ビット整数です。32ビット演算は、x86では16ビット演算よりも全体的に高速であるためです。
プラットフォームに関係なく、プログラムが実行する計算の結果を保持できる型を使用できるはずなので、これはすべて重要です。整数オーバーフローの違いにより、プログラムがあるプラットフォームでは正しい結果を生成し、別のプラットフォームでは正しくない結果を生成する場合、それは悪いことです。標準の整数型を使用することにより、使用される整数のサイズに関して、異なるプラットフォームでの結果が同じであることを保証します(もちろん、プラットフォーム間に他の違いがある可能性があります)整数幅)。
したがって、はい、long
は最新のC++コードから禁止する必要があります。 int
、short
、long long
。
いいえ、組み込みの整数型を禁止するのはばかげています。しかし、彼らは虐待されるべきではありません。
正確にである整数が必要な場合 N ビット幅、std::intN_t
(またはunsigned
バージョンが必要な場合はstd::uintN_t
)を使用します。 int
を32ビット整数として、long long
を64ビット整数として考えるのは間違っています。現在のプラットフォームではこのようになる可能性がありますが、これは実装定義の動作に依存しています。
固定幅整数型の使用は、他のテクノロジーとの相互運用にも役立ちます。たとえば、アプリケーションの一部がJavaで記述され、その他がC++で記述されている場合、整数型を一致させて一貫した結果を得ることができます。( Javaはセマンティクスが明確に定義されていますが、C++のsigned
オーバーフローは未定義の動作であるため、一貫性が高い目標です。)異なるコンピューティングホスト間でデータを交換する場合にも重要です。
正確に必要ない場合 N ビット、ただし十分に広いのタイプのみの場合は、std::int_leastN_t
(スペース用に最適化)またはstd::int_fastN_t
(速度用に最適化)の使用を検討してください。繰り返しますが、両方のファミリにもunsigned
の対応物があります。
それで、組み込み型をいつ使うのですか?さて、規格はそれらの幅を正確に指定していないので、しないでください実際のビット幅ではなく他の特性に注意するときにそれらを使用してください。
char
は、ハードウェアがアドレス可能な最小の整数です。言語は実際には、任意のメモリのエイリアスに使用することを強制します。また、(狭い)文字列を表すための唯一の実行可能なタイプでもあります。
int
は通常、マシンが処理できる最高速のタイプです。これは、1つの命令で(ビットをマスクしたりシフトしたりせずに)ロードおよび格納できるほど十分に広く、(最も)効率的なハードウェア命令で操作できるように十分に狭くなります。したがって、int
は、データを渡し、オーバーフローが問題にならない場合に算術演算を行うのに最適な選択肢です。たとえば、列挙型のデフォルトの基本タイプはint
です。可能であれば、32ビット整数に変更しないでください。また、–1、0、および1のみにできる値がある場合は、int
が最適な選択肢です。ただし、それらの巨大な配列を格納する場合を除いて、個々の要素にアクセスするために高い価格を支払う必要があるという犠牲を払って、よりコンパクトなデータ型。より効率的なキャッシングは、おそらくこれらに報いるでしょう。多くのオペレーティングシステム関数もint
で定義されています。彼らの議論と結果を前後に変換するのはばかげたことでしょう。これはおそらく導入オーバーフローエラーです。
long
は通常、単一の機械語命令で処理できる最も広い型になります。これは、特にunsigned long
を生データやあらゆる種類のビット操作に関するものを扱うために非常に魅力的にします。たとえば、ビットベクトルの実装でunsigned long
が表示されることを期待しています。コードが慎重に記述されている場合、タイプが実際にどのくらい広いかは問題ではありません(コードが自動的に適応するため)。ネイティブマシンワードが32ビットであるプラットフォームでは、ビットベクトルのバッキング配列をunsigned
32ビット整数の配列にすることが最も望ましいです。とにかく不要なビットをシフトしてマスクするためだけに、高価な命令を介してロードされます。一方、プラットフォームのネイティブのWordサイズが64ビットの場合、「最初のセットを見つける」などの操作が最大2倍の速度で実行される可能性があるため、そのタイプの配列が必要です。したがって、あなたが説明しているlong
データ型の「問題」は、そのサイズがプラットフォームごとに異なり、実際にはfeatureであり、十分に使用できます。これは、組み込み型を特定のビット幅の型と考えた場合にのみ問題になります。
char
、int
およびlong
は、上記のように非常に便利なタイプです。 short
とlong long
は、セマンティクスがあまり明確でないため、それほど有用ではありません。
別の答えは、cstdint型とその中のあまり知られていないバリエーションについてすでに詳述しています。
私はそれに追加したいと思います:
つまり、パラメーターと変数をuint32_t
(確かにlong
!ではない)と宣言せずに、channel_id_type
、room_count_type
などの名前を付けます。
long
またはwhatnotを使用するサードパーティのライブラリは、特にそれらへの参照またはポインタとして使用される場合、煩わしい場合があります。
bestはラッパーを作ることです。
私の戦略は、一般に、使用されるキャストのような関数のセットを作成することです。それらはオーバーロードされ、対応する型と完全に一致する型だけを受け入れ、必要なポインタなどのバリエーションも受け入れます。これらはos/compiler/settingsに固有に定義されています。これにより、警告を削除しながら、「正しい」変換のみが使用されるようにすることができます。
channel_id_type cid_out;
...
SomeLibFoo (same_thing_really<int*>(&cid_out));
特に、32ビットを生成するさまざまなプリミティブ型では、int32_t
の定義方法の選択がライブラリー呼び出しと一致しない場合があります(Windowsのintとlongなど)。
キャストのような関数documentsクラッシュ、関数のパラメーターに一致する結果のコンパイル時チェックを提供し、警告またはエラーを削除しますif if only only実際のタイプ関連する実際のサイズに一致します。つまり、(Windowsで)int*
またはlong*
を渡すとオーバーロードされて定義され、そうでない場合はコンパイル時エラーが発生します。
したがって、ライブラリが更新されたり、誰かがchannel_id_type
を変更した場合、これは引き続き検証されます。