C/C++における整数型には気をつけよ

注意: この記事は1年以上前に掲載されたものです。情報が古い場合がありますのでお気を付け下さい。

C言語とC++では整数を扱う型として、intをはじめ、longやshort型などが扱われている。ちなみに、これらは実際には一定のバイト幅のメモリーに割り当てられるのだが、これが実に曲者で、実際の環境に応じてそれぞれの型でビット幅のサイズが異なるという実装任せの仕様になっており、これが原因で移植性に悪影響を及ぼすことが往々にしてある。

C/C++における型と実際のビット幅

C言語およびC++言語においては、実装状況に応じて実際に扱われているビット幅が変わっている。今日のコンピューターでは8bit=1byteとして扱われているものが多いことと、現在のコンピューターでは32ビットまたは64ビットのアーキテクチャーが主流となっているため、それを前提に説明する。

C言語の仕様においては、整数型char、short、int、long、long longの型はいずれもサイズまでは指定されておらず、実装によってまちまちとなっている。これは暴論だが、char ≦ short ≦ int ≦ long ≦ long longであること以外は実際のサイズはわからないといわざるを得ないほどである。ただし、移植性を考えるにあたって、各仕様ごとに変数の型と実際のサイズがバラバラになっているのでは、特にポインタを演算するなどをの面でオーバーフローを起こしたりするなど支障をきたす可能性がある。

ちなみに、今日のコンピューターでは32bit、64bitでそれぞれ以下のデータ型モデルが採用されている。

32ビットアーキテクチャー

  • LP32 – long型、ポインター型が32bit(4byte)(int型が16bit(2byte))。実装例はほとんどない。
  • ILP32 – int型、long型、ポインター型が32bit(4byte)。WindowsやUnix系(OS X含む)などメジャーな32bitのOSのほぼ全がこれが採用されている。

64ビットアーキテクチャー

  • LLP64 – long long型、ポインター型が64bit(8byte)(int型とlong型が32bit(4byte))。64bit版Windowsはこれを採用している。
  • LP64 – long型、long long型、ポインター型が64bit(8byte)(int型が32bit(4byte))。OS Xを含めた64bit版のUnix系OSの多くがこれを採用している。
  • ILP64 – int型、long型、long long型、ポインター型が64bit(8byte)。実装例はほとんどなく、4byte型を使用する場合はint32_tを使わなければならない。

各変数と実際のビットサイズ表

整数型 LP32 ILP32 LLP64 LP64 ILP64
char 8 8 8 8 8
short 16 16 16 16 16
int 16 32 32 32 64
long 32 32 32 64 64
long long 64 64 64 64 64

C99/C++11ではサイズが保証される型が用意されている

上記のことから、整数型では実際の環境によって実際のサイズが異なるため、それの対策のため、C99とC++11では以下の環境非依存の型が準備された。

  • int8_t/uint8_t – 8bit (1byte)
  • int16_t/uint16_t – 16bit (2byte)
  • int32_t/uint32_t – 32bit (4byte)
  • int64_t/uint64_t – 64bit (8byte)
  • intptr_t/uintptr_t – ポインター型(32bit環境なら32bit、64bit環境なら64bit)

環境に応じて型のサイズを固定させたい場合は上記の型を使用するのが望ましい。またこうすることによって移植性が格段に向上する。

特にintptr_tおよびuintptr_t型は今後アドレスの計算に必須要素となるだろう。

C99およびC++11を使用しているのであれば今後はなるべく環境に依存しない変数型を使うようにしよう。

タイトルとURLをコピーしました