web-dev-qa-db-ja.com

stdintを使用する(または使用しない)理由

プラットフォーム間の移植性のために特定の変数サイズが必要なときにstdintが使用されることは既に知っています。私は今のところ本当にそのような問題を抱えていませんが、上記の既に示した事実以外にそれを使用することの短所と長所は何ですか?

Stackoverflowおよび他のサイトでこれを探して、テーマに関する2つのリンクを見つけました。

  • codealias.info -これは、stdintのポータビリティについて説明しています。

  • stackoverflow -これはuint8_tについてより具体的です。

この2つのリンクは、このヘッダーの主な理由-portabilityについて詳しく知りたい場合に特に役立ちます。しかし、私にとって最も好きなのは、_uint8_t_は_unsigned char_よりもきれいだと思うことです(たとえば、RBGチャネル値を格納するため)、_int32_t_は単にintなど.

だから、私の質問は、移植性以外にstdintを使用することの長所と短所は何ですか?コードの特定の部分だけで使用する必要がありますか?どこでも、atoi()strtok()などの関数を使用するにはどうすればよいですか?

ありがとう!

45
Sassa

長所

たとえば、あるマシンがintを16ビットとして解釈し、別のマシンが32ビットとして解釈する場合に驚くことはないため、明確に定義された型を使用すると、コードの移植がはるかに簡単で安全になります。 stdint.hを使用すると、入力した内容が取得されます。

intなどを使用すると、危険なタイプのプロモーションを検出することも難しくなります。

別の利点は、charの代わりにint8_tを使用することで、常に符号付き8ビット変数を取得できることです。 charは、署名付きでも署名なしでもかまいません。実装定義の動作であり、コンパイラによって異なります。したがって、デフォルトのcharは、移植性のあるコードで使用するのは非常に危険です。

変数を最適化する必要があるというコンパイラのヒントを提供したい場合、uint_fastx_tを使用して、少なくとも 'x'と同じ大きさの、可能な限り速い整数型を使用するようコンパイラに指示できます。ほとんどの場合、これは重要ではありません。コンパイラは、入力した内容に関係なく型サイズを最適化するのに十分スマートです。シーケンスポイント間で、コンパイラは型を指定されたもの以外に暗黙的に変更できます結果には影響しません。

短所

なし。


参照:MISRA-C:2004規則6.3。「typedefsは、基本型の代わりにサイズと符号付きを示す」.

編集:間違った例を削除しました。

69
Lundin

_uint8_t_ではなく_unsigned char_を使用する唯一の理由は(審美的な好みは別として)プログラムがcharが正確に8ビットである必要があることを文書化する場合です。 _uint8_t_は、C標準の要件に従って、_CHAR_BIT==8_の場合にのみ存在します。

残りの_intX_t_および_uintX_t_型は、次の状況で役立ちます。

  • ディスク/ネットワークの読み取り/書き込み(ただし、エンディアン変換関数も使用する必要があります)
  • 正確なカットオフで符号なしのラップアラウンド動作が必要な場合(ただし、これは_&_演算子を使用するとより移植性が高くなります)。
  • パディングが存在しないことを確認する必要があるため、構造体の正確なレイアウトを制御しているとき(たとえば、memcmpまたはハッシュ目的)。

一方、_uint_least8_t_などのタイプは、無駄に大きいまたは遅いタイプの使用を避けたいが、特定の大きさの値を格納できるようにする必要がある場合に便利です。たとえば、_long long_は少なくとも64ビットですが、一部のマシンでは128ビットになる可能性があり、必要なのが64ビットの数値を格納できるタイプだけである場合、そのようなマシンでは非常に無駄になります。 _int_least64_t_は問題を解決します。

_[u]int_fastX_t_型は、特定のマシンで変更を使用することがあり(ABIを壊す)、定義が通常間違っているため、_int32_t_型を完全に使用することは避けます。たとえば、x86_64では、64ビット整数型は16、32、および64ビット値の「高速」と見なされますが、32を使用しても、加算、減算、乗算はまったく同じ速度ですビット値または64ビット値の場合、必要以上のタイプの場合、除算はほぼ確実に遅くなり、同じ速度であっても、メモリを2倍使用してもメリットはありません。

最後に、ネイティブ整数サイズではないときにカウンターに_size_t_を使用することの非効率性に関するいくつかの答えが、技術的にはほとんど正しいが、コードを修正することは無関係であることに注意してください。最大カウントがあなたの制御下にあるいくつかの少数のもの、またはカウントが天文学的なかもしれない外部(プログラムのメモリ内ではない)のものをカウントしていない限り、カウントの正しい型はほとんど常に__(SOMECODE)です__。これが、すべての標準C関数がカウントに_size_t_を使用する理由です。特別な理由がない限り、他のものの使用を検討しないでください。

16
R..

短所

C言語がintlongなどのサイズを指定しない主な理由は、計算効率のためです。各アーキテクチャには自然で最も効率的なサイズがあり、設計者はコンパイラの実装者が自然なネイティブデータサイズデータを使用して速度とコードサイズの効率を高めるように特別に権限を与え、意図しました。

過去において、他のマシンとの通信は主要な関心事ではなく、ほとんどのプログラムはマシンにローカルであったため、各データタイプのサイズの予測可能性はほとんど関心がありませんでした。

特定のアーキテクチャが特定のサイズintを使用してカウントすることを主張することは、他のことをより簡単にすると思われる場合でも、本当に悪い考えです。

ある意味では、XMLとその仲間のおかげで、データ型のサイズは再び大きな問題ではなくなりました。マシン固有のバイナリ構造をマシンからマシンに出荷することも、ルールではなく例外です。

7
wallyk

メモリに保持しているデータがバイナリ形式でディスク/ネットワーク/ディスクリプターに保存される場合、1つの理由でのみstdint型を使用します。リトルエンディアン/ビッグエンディアンの問題と戦う必要があるだけですが、それは比較的 克服しやすい です。

Stdintを使用する明白な理由notは、コードがサイズに依存しない場合、数学的には有理整数で機能するすべてのものです。 _uint*_t_のすべての展開に対して、たとえばqsort()の_*_バージョンを提供すると、いコード重複が生成されます。

その場合は、怠けているときに_size_t_から派生した独自の型を使用し、そうでない場合はプラットフォームでサポートされている最大の符号なし整数を使用します。

先にこの問題に遭遇したので編集してください:
Solaris 2.0.1では、少なくとも_uint8_t_、_uint32_t_、および_uint64_t_が破損していることは注目に値すると思います。したがって、移植性を最大限にするために、_stdint.h_を避けることをお勧めします(少なくとも今後数年間は)。

6
hroptatyr