32 ビットと 64 ビットの両方のコンパイル環境でコードを安全にするためにシステム派生型を使用することは、良いプログラミング方法です。派生データ型を使用するときに、データ型モデルの変更または移植のためにはシステム派生型だけを変更する必要があります。
システムインクルードファイルの <sys/types.h> および <inttypes.h> には、32 ビットと 64 ビットのどちらにも安全なアプリケーションの作成に役立つ定数、マクロ、派生型が含まれています。
アプリケーションのソースファイルに <sys/types.h> をインクルードして、_LP64 および _ILP32 の定義を使用できるようにしてください。このヘッダーには、必要に応じて使用される基本派生型もいくつか含まれています。特に次は大切です。
clock_t クロックの刻み数でシステム時間を表します。
dev_t デバイス番号に使用されます。
off_t ファイルのサイズとオフセットに使用されます。
ptrdiff_t 2 つのポインタの減算結果用の符号付き整数型です。
size_t メモリー上のオブジェクトのサイズをバイト数で表します。
ssize_t バイト数あるいはエラー発生通知を返す関数によって使用されます。
time_t 秒数で時間をカウントします。
これらの派生型はすべて、ILP32 コンパイル環境では 32 ビット量のままですが、LP64 コンパイル環境では、64 ビット量になります。
<inttypes.h> インクルードファイルには、コンパイル環境に関係なく、明示的にサイズ指定されたデータ項目との互換性を持たせるのに役立つ定数、マクロ、派生型が含まれています。このファイルには、8、16、32、64 ビットオブジェクトを操作するための仕組みも含まれています。<inttypes.h> に含まれることが議論されている基本機能としては、次のものがあります。
固定幅の整数型。
uintptr_t などの便利な型
定数マクロ
制限
書式文字列マクロ
以降のセクションで、<inttypes.h> のこれらの基本機能について詳しく説明します。
<inttypes.h> が提供する固定幅の整数型には、int8_t、int16_t、int32_t、int64_t などの符号付整数型と、uint8_t、uint16_t、uint32_t、uint64_t などの符号なし整数型が含まれます。
指定数のビットを保持できる最小サイズの整数型として定義されている派生型には、int_least8_t、…、int_least64_t、uint_least8_t、…、uint_least64_t が含まれます。
ループカウンタやファイル記述子などの演算に int または unsigned int を使用することは安全です。配列インデックスに long を使用することも安全です。しかし、これらの固定幅型はむやみに使用しないでください。固定幅の型は、次の項目の明示的なバイナリ表現に使用してください。
ディスク上のデータ
データ回線上のデータ
ハードウェアレジスタ
バイナリのインタフェース仕様
バイナリのデータ構造体
<inttypes.h> ファイルには、ポインタを保持するのに十分な大きさの符号付き整数型と符号なし整数型が含まれています。これらは intptr_t および uintptr_t として指定されます。また、<inttypes.h> は符号付きと符号なし整数型の中で最長 (ビット) の整数型である intmax_t と uintmax_t も提供します。
uintptr_t 型は、unsigned long などの基本型ではなく、ポインタ用の整数型として使用してください。ILP32 と LP64 の両方のデータ型モデルで unsigned long がポインタと同じサイズであるとしても、uintptr_t を使用することは、データ型モデルが変わった場合に、uintptr_t の定義だけが影響を受けることを意味します。この方法は、コードをほかの多くのシステムに移植可能にし、意図を C で表現するためのより明確な方法でもあります。
intptr_t および uintptr_t 型は、アドレス演算でポインタの型変換を行うときに大変役立ちます。この目的には、long や符号なし long ではなく、intptr_t と uintptr_t 型を使用してください。
定数のサイズと符号の指定には、INT8_C(c) … INT64_C(c)、UINT8_C(c) … UINT64_C(c) マクロを使用してください。基本的に、これらのマクロは、必要に応じて定数の末尾に l、ul、ll、ull という文字列を追加します。たとえば INT64_C(1) は、ILP32 では定数 1 に ll、LP 64 では l を付加します。
定数を最大型にするときは、INTMAX_C(c) と UINTMAX_C(c) を使用してください。これらのマクロは、LP64 データ型モデルへの変換で説明している定数型を指定する際に大変役立ちます。
<inttypes.h> で定義されている上下制限は、いろいろな整数型の最小値と最大値を指示する定数です。これらの制限には、INT8_MIN … INT64_MIN、INT8_MAX … INT64_MAX などの各固定幅型とそれらに対応する符合なし型に対する、最小値と最大値が含まれます。
<inttypes.h> ファイルは、最小サイズのそれぞれの型に対する最小値と最大値も提供します。これらの型には、INT_LEAST8_MIN … INT_LEAST64_MIN、INT_LEAST8_MAX … INT_LEAST64_MAX 型やそれらに対応する符号なし型が含まれます。
最後に、<inttypes.h> は、サポートされる最大整数型の最小値と最大値を定義します。これらの型には、INTMAX_MIN と INTMAX_MAX、およびそれらに対応する符号なし型が含まれます。
<inttypes.h> ファイルには printf(3S) および scanf(3S) 書式指定子を指定するマクロが含まれています。基本的にこれらのマクロは、引数のビット数がマクロ名に組み込まれていることを条件に、書式指定子の前に l または ll を付加して、引数が long または long long のどちらであるかを示します。
次の例で示すように、printf(3S) 用の一部のマクロは、最小整数型と最大整数型の両方を 10 進、8 進、符号なし、および 16 進の形式で出力します。
int64_t i; printf("i =%" PRIx64 "\n", i);
同様に、scanf(3S) 用のマクロは、最小整数型と最大整数型の両方を 10 進、8 進、符号なし、および 16 進の形式で読み取ります。
uint64_t u; scanf("%" SCNu64 "\n", &u);
これらのマクロはむやみに使用しないでください。固定幅の整数型で説明しているように、固定幅型に対して使用するのがもっとも適しています。