11

私は、複数のデスクトップおよびモバイル プラットフォーム間で移植可能にする必要があるいくつかの C および C++ プロジェクトを開発しています。u32_t i64_ディスクにデータを読み書きするときは、明示的にサイズ設定された型 t などを使用することが重要であることを知っています。

一貫した実行を保証するために、すべての整数型の明示的なサイズの型を使用することは良い考えでしょうか? プロセッサは期待される型などに合わせて最適化されているため、明示的にサイズ設定された型はパフォーマンスに影響を与える可能性があると聞いたことがintあります。また、インターフェイスではなく、クラス データ メンバーに対して明示的にサイズ設定された型を内部で使用することをお勧めします。

データ メンバーとインターフェイスの明示的なサイズの型に関するベスト プラクティスはありますか? (これらの状況では、C と C++ の間に大きな違いはないと思いますが、あれば教えてください)

4

4 に答える 4

12

基本的な「int」型の良いところは、現在コンパイルしているプラ​​ットフォームに関係なく、ほぼ常に最速の整数型になることです。

一方、たとえば int32_t (単なる int の代わりに) を使用する利点は、コンパイルされたプラットフォームに関係なく、int32_t が常に 32 ビット幅であることをコードが期待できることです。つまり、より多くの仮定を安全に行うことができます。 int を使用した場合よりも値の動作について。固定サイズの型では、コードが新しいプラットフォーム Y でコンパイルされた場合、古いプラットフォーム X で行ったのとまったく同じように動作する可能性が高くなります。

int32_t の (理論上の) 欠点は、新しいプラットフォーム X が 32 ビット整数をサポートしない可能性があることです (その場合、コードはそのプラットフォームでまったくコンパイルされません)。古い整数。

ほとんどすべての最新のハードウェアは 32 ビット整数を全速力で処理するため、上記の例は少し不自然ですが、int64_ts の操作が int の操作よりも遅いプラットフォームが実際に (そして実際に) 存在します。したがって、各操作を複数のステップに分割する必要があります。もちろん、(b) 64 ビット整数は 32 ビット整数の 2 倍のメモリを占有し、キャッシュに余分な圧力をかける可能性があります。

ただし、人々が作成したソフトウェアの 99% については、この問題がパフォーマンスに目に見える影響を与えることはないことに注意してください。つまり、integer-width が大きなパフォーマンスの問題になる可能性は低いです。要するに、整数演算をどのように動作させたいかということです

  • 整数値が常に 32 ビットの RAM を占有し、コンパイルしているプラ​​ットフォームに関係なく、常に 2^31 (または符号なしの場合は 2^32) で「ラップアラウンド」することをコンパイラーに保証させたい場合は、次のようにします。 int32_t (など) を使用します。

  • ラッピング動作をあまり気にせず (格納しているデータの性質上、整数が決してラップされないことがわかっているため)、奇数/異常なコンパイル ターゲットに対してコードをもう少し移植しやすくしたい場合、そして少なくとも理論的にはより高速です(おそらく実際にはそうではありませんが)。

個人的には、固定サイズの型 (int32_t など) をデフォルトで使用していますが、そうしない明確な理由がある場合を除きます。これは、プラットフォーム全体でのバリアント動作の量を最小限に抑えたいためです。たとえば、次のコード:

for (uint32_t i=0; i<4000000000; i++) foo();

... 常に foo() を正確に 4000000000 回呼び出しますが、このコードは次のとおりです。

for (unsigned int i=0; i<4000000000; i++) foo();

(sizeof(int)>=4) かどうかによって、foo() を 4000000000 回呼び出すか、無限ループに入る可能性があります。確かに、2 番目のスニペットが特定のプラットフォームでそれを行わないことを手動で検証することは可能ですが、いずれにせよ 2 つのスタイル間のパフォーマンスの差がほぼゼロであることを考えると、その動作を予測することはノーであるため、最初のアプローチを好みます。より簡単に。char/short/int/long アプローチは、コンピューター アーキテクチャがより多様であり、CPU が十分に遅く、安全なコーディングよりも完全なネイティブ パフォーマンスを達成することが重要だった C の初期の頃に、より有用であったと思います。

于 2012-04-19T21:36:42.267 に答える
6

inttypes.hまたはを使用しstdint.hます。ANSI-C であるため、ANSI 準拠を目指すツールチェーンでサポートされます。

さらに、車輪を再発明する手間も省けます。

あなたがしなければならない唯一のことは

#include <inttypes.h>

uint32_t integer_32bits_nosign;
  • 移植性に関するもう 1 つの懸念事項: データ幅がデータ エンディアンであるため、非常に重要です。標準マクロでターゲットのエンディアンを確認する必要があります。

    struct {
    #if defined( __BIG_ENDIAN__ ) || defined( _BIG_ENDIAN )
        // Data disposition for Big Endian   
    #else
        // Data disposition for Little Endian   
    #endif
    };
    

ビットフィールドを使用する場合、特に敏感です。


編集:

もちろん<csdtint>、C++ のみのコードで使用する場合は、他の人が提案したように使用できます。

于 2012-04-19T18:40:08.223 に答える
1

固定サイズの型に関するかなり厄介な「落とし穴」は、コードが「int」のサイズに依存していないという印象を与える一方で、それは実際には錯覚であるということです。次のようなコード:

uint32_t mul(uint16_t a, uint16_t b)
{ return a*b; }

"int" が 40 ビット以上のすべてのプラットフォームで、"a" と "b" のすべての値に対して定義された意味を持ち、" int" は 16 ビットですが、算術積が 65535 の場合は意味が異なります。 C89 標準の作成者は、そうする必要はありませんが、その時代の実装の大部分は整数演算の動作をほとんどの結果が INT_MAX+1 と UINT_MAX の間にある場合でも、符号付き演算は、いくつかの特定の例外を除いて、符号なしの対応する演算と同じように動作します。-- したがって、これらのコンパイラでは、"a" と "b" のすべての値の動作は、より大きな "int" 型のマシンでの動作と一致します。ただし、32 ビット コンパイラが INT_MAX より大きい値で壊れるコードを生成することは流行になっています。これは、標準で禁止されていないためです。

于 2016-04-12T07:44:53.247 に答える