C++言語を初めて学んだとき、int、floatなどの他に、これらのデータ型の小さいバージョンまたは大きいバージョンが言語内に存在することを知りました。たとえば、変数xを呼び出すことができます
int x;
or
short int x;
主な違いは、short intは2バイトのメモリを使用するのに対し、intは4バイトを使用し、short intの方が値が小さいことですが、これを呼び出してさらに小さくすることもできます。
int x;
short int x;
unsigned short int x;
これはさらに制限的です。
ここでの私の質問は、プログラム内で変数が取る値に応じて、別々のデータ型を使用するのが良い方法かどうかです。これらのデータ型に従って常に変数を宣言することは良い考えですか?
ほとんどの場合、スペースコストはごくわずかなので、心配する必要はありませんが、型を宣言することによって提供する追加情報を心配する必要があります。たとえば、次の場合:
unsigned int salary;
あなたは別の開発者に有用な情報を提供しています。給与がマイナスになることはありません。
Short、int、longの違いがアプリケーションでスペースの問題を引き起こすことはほとんどありません。数値があるデータ型に常に適合するという誤った仮定を誤って行う可能性が高くなります。数値が常に非常に小さいことを100%確信していない限り、常にintを使用する方が安全です。それでも、目立ったスペースを節約することはできません。
OPはプログラムを作成するシステムの種類については何も述べていませんが、C++について言及されているため、OPはGBのメモリを備えた典型的なPCを考えていたと思います。コメントの1つが言うように、そのようなメモリがあっても、配列など、1つのタイプのアイテムが数百万ある場合、変数のサイズによって違いが生じる可能性があります。
組み込みシステムの世界に入った場合、OPはPCに限定されないため、これは問題の範囲外ではありません-データ型のサイズは非常に重要です。 8Kワードのプログラムメモリと368 bytes RAMしかない8ビットマイクロコントローラーで簡単なプロジェクトを完了しました。そこでは、明らかにすべてのバイトがカウントされます。必要以上に大きな変数を使用することは決してありません(スペースの観点からも、コードサイズも-8ビットプロセッサは16および32ビットデータを操作するために多くの命令を使用します)。なぜこのような限られたリソースでCPUを使用するのですか?大量の場合、4分の1のコストで済みます。
私は現在、512Kバイトのフラッシュと128KバイトのRAMの32K MIPSベースのマイクロコントローラーを使用して、別の組み込みプロジェクトを行っています(RAMの数量は約$ 6です)。PCと同じです。 、「自然な」データサイズは32ビットです。charやshortの代わりに、ほとんどの変数にintを使用する方がコード的に効率的です。しかし、繰り返しになりますが、データのサイズが小さいかどうかにかかわらず、あらゆるタイプの配列または構造を考慮する必要があります。型は保証されます。大規模なシステムのコンパイラとは異なり、構造内の変数が組み込みシステムにパックされる可能性が高くなります。すべての32ビット変数を最初に配置し、次に16ビット、次に8ビットを配置して「ホール」を回避します。
答えはシステムによって異なります。一般的に、小さい型を使用する利点と欠点は次のとおりです。
メリット
短所
私のアドバイスは次のようにすることです:
system int types
small/low level embedded system stdint.h with smaller types
32-bit embedded system stdint.h, stick to int32_t and uint32_t.
32-bit desktop system Only use (unsigned) int and long long.
64-bit system Only use (unsigned) int and long long.
または、int_leastn_t
またはint_fastn_t
stdint.hから。nは8、16、32、または64の数値です。int_leastn_t
タイプは、「これを少なくともnバイトにしたいが、コンパイラーがアライメントに合わせてより大きなタイプとして割り当ててもかまわない」ことを意味します。
int_fastn_t
は、「これをnバイト長にしたいが、コードの実行が速くなる場合、コンパイラーは指定よりも大きい型を使用する必要がある」ことを意味します。
一般に、さまざまなstdint.h型は、移植性があるため、プレーンなint
などよりもはるかに優れています。 int
の意図は、移植可能にするためだけに特定の幅を指定しないことでした。しかし、実際には、特定のシステムでどれほど大きくなるかわからないため、移植するのは困難です。
特定のオペレーティングシステムの動作方法に応じて、通常、メモリが最適化されていない状態で割り当てられ、バイトを要求したり、Wordやその他の小さなデータ型を割り当てたりすると、値がレジスタ全体を占めるようになります。自分の。ただし、コンパイラまたはインタープリターがこれを解釈する方法は何か別のものです。たとえば、C#でプログラムをコンパイルする場合、値自体がレジスターを物理的に占有する可能性がありますが、値が境界チェックされていないことを確認します目的のデータ型の境界を超える値を格納しようとします。
パフォーマンスに関して、そしてそのようなことについて本当に精通している場合は、ターゲットレジスタサイズに最も近いデータ型を使用するほうが速い可能性がありますが、変数の操作を非常に簡単にする素敵な構文上の糖をすべて見落としています。 。
これはどのように役立ちますか?ええと、コーディングする状況の種類を決めるのは本当にあなた次第です。これまでに書いたほとんどすべてのプログラムについて、コンパイラーを信頼して物事を最適化し、最も役立つデータ型を使用するだけで十分です。高精度が必要な場合は、より大きな浮動小数点データ型を使用してください。正の値のみを扱う場合は、おそらく符号なし整数を使用できますが、ほとんどの場合、intデータ型を使用するだけで十分です。
ただし、通信プロトコルの記述や何らかの暗号化アルゴリズムなど、非常に厳しいデータ要件がある場合は、特にデータのオーバーラン/アンダーランに関連する問題を回避しようとする場合、範囲チェックされたデータ型を使用すると非常に便利です。 、または無効なデータ値。
私が頭の中で特定のデータ型を使用することを考えることができる他の唯一の理由は、コード内で意図を通信しようとしているときです。たとえば、shortintを使用する場合、他の開発者に、非常に小さな値の範囲内で正と負の数を許可することを伝えています。
scarfridge がコメントしたように、これは
時期尚早の最適化 の古典的なケース。
メモリ使用量を最適化しようとするとmightはパフォーマンスの他の領域に影響を与えます 最適化のゴールデンルール は次のとおりです:
プログラム最適化の最初のルール:それをしないでください。
プログラム最適化の2番目のルール(エキスパートのみ!):まだ実行しないでください。 "
—マイケルA.ジャクソン
今が最適化の時かどうかを知るには、ベンチマークとテストが必要です。最適化をターゲットにできるように、コードのどこが非効率的であるかを知る必要があります。
最適化コードのバージョンisが実際のナイーブ実装よりも実際に優れているかどうかを判断するには、同じように並べてベンチマークする必要がありますデータ。
また、特定の実装が現在の世代のCPUでより効率的であるからといって、それがalwaysになるとは限らないことも覚えておいてください。 私の答え 質問へ コーディング時にマイクロ最適化は重要ですか? は、廃止された最適化によって桁違いのスローダウンが発生した個人的な経験の例を詳しく説明しています。
多くのプロセッサでは、非整列メモリアクセスは大幅に整列メモリアクセスよりもコストがかかります。構造体にいくつかのショートをパックすることは、プログラムがパック/アンパック操作を実行する必要があることを意味するだけかもしれません毎回どちらかの値に触れます。
このため、最新のコンパイラーはユーザーの提案を無視します。 nikie コメント:
標準のパッキング/アラインメントコンパイラ設定では、変数はいずれにしても4バイト境界にアラインメントされるため、まったく違いがない場合があります。
次に、危険にさらされているコンパイラを推測します。
テラバイトのデータセットや組み込みのマイクロコントローラーを操作する場合、そのような最適化のための場所がありますが、私たちのほとんどにとって、それは本当に問題ではありません。
これは、ある種のOOPおよび/または企業/アプリケーションの観点からのものであり、特定のフィールド/ドメインには適用されない可能性がありますが、私は原始的な執着。
ISアプリケーションでさまざまな種類の情報にさまざまなデータ型を使用することをお勧めします。ただし、深刻な問題がない限り、組み込み型を使用することはおそらくお勧めできません。パフォーマンスの問題(測定および検証済みなど)。
アプリケーションでケルビンの温度をモデル化したい場合は、ushort
またはuint
または「負の度数ケルビンの概念は不合理であり、ドメインロジックエラーである」ことを示すようなものを使用できます。この背後にあるアイデアは健全ですが、あなたはすべての道を行きません。私たちが気付いたことは、負の値を持つことはできないということです。そのため、ケルビン温度に負の値を割り当てないようにコンパイラーに依頼できると便利です。また、温度に対してビット演算を実行できないことも事実です。また、温度(K)に重量(kg)を追加することはできません。しかし、温度と質量の両方をuint
sとしてモデル化すると、それを行うことができます。
組み込み型を使用してDOMAINエンティティをモデル化すると、いくつかの厄介なコードやいくつかのチェックの欠落や不変条件の破損につながる可能性があります。型がエンティティの一部をキャプチャする場合でも(負にすることはできません)、他の型が欠落する可能性があります(任意の算術式で使用できない、ビットの配列として処理できないなど)。
解決策は、encapsulatesが不変である新しい型を定義することです。このようにして、お金がお金であり、距離が距離であることを確認できます。それらを加算することはできません。負の距離を作成することはできませんが、負の金額(または借金)を作成することはできます。もちろん、これらの型は組み込み型を内部的に使用しますが、これはクライアントからのhiddenです。パフォーマンス/メモリ消費に関する質問に関して、この種の事柄により、ドメインエンティティを操作する関数のインターフェイスを変更せずに、内部に格納する方法を変更できます。short
も同様です。いまいましい。
主な違いは、short intは2バイトのメモリを使用するのに対し、intは4バイトを使用し、short intの方が値が小さいことですが、これを呼び出してさらに小さくすることもできます。
これは誤りです。 char
が1バイトでバイトあたり少なくとも8ビットであり、かつ各タイプのサイズが前のサイズ以上である場合を除いて、各タイプが保持するバイト数を推測することはできません。
スタック変数のパフォーマンスのメリットは非常に小さく、とにかく整列/パディングされる可能性があります。
このため、現在short
とlong
はほとんど使用されておらず、ほとんどの場合int
を使用する方がベターです。
もちろん、stdint.h
は、int
がそれをカットしないときに使用するのにまったく問題ありません。整数/構造体の巨大な配列を割り当てている場合、intX_t
は効率的でタイプのサイズに依存できるため、理にかなっています。メガバイトのメモリを節約できるので、これは決して時期尚早ではありません。
はい、もちろん。辞書、巨大な定数配列、バッファなどにはuint_least8_t
を使用することをお勧めします。処理目的にはuint_fast8_t
を使用することをお勧めします。
uint8_least_t
(ストレージ)-> uint8_fast_t
(処理)-> uint8_least_t
(ストレージ)。
たとえば、source
から8ビットのシンボル、dictionaries
から16ビットのコード、およびいくつかの32ビットconstants
を取得します。それらを使用して10〜15ビットの演算を処理し、8ビットのdestination
を出力します。
2ギガバイトのsource
を処理する必要があるとしましょう。ビット操作の量は膨大です。処理中に高速タイプに切り替えると、優れたパフォーマンスボーナスを受け取ります。高速タイプは、CPUファミリごとに異なる場合があります。 stdint.h
を含めて、uint_fast8_t
、uint_fast16_t
、uint_fast32_t
などを使用できます。
移植性のために、uint_least8_t
の代わりにuint8_t
を使用できます。しかし 実際には誰も知りません この機能を使用する最新のCPUは何ですか。 VAC機械は美術館の作品です。多分それはやり過ぎです。