整数の内部表現

これまで習った整数型には char, int, long がある。 実際にはこれらをより細かく分類した整数型がある。

符号と長さ

厳密には整数型は、負の数を扱い得るか(符号を持つか)と それを何ビットのメモリで表すかを続けて指定して宣言する規則になっている。

ここに挙げたビット数と宣言の型名対応はgccの場合である。 別のC言語処理系の場合は対応がずれる場合がある。

負の数を使う場合、使わない場合について、各ビット数で表現できる 整数の上限下限は以下のようになる。

ビット数符号あり符号なし
8ビット-128〜1270〜255
16ビット-32768〜327670〜65535
32ビット -2147483648〜21474836470〜4294967295
約43億
64ビット 9223372036854775808〜9223372036854775808 0〜18446744073709551615
約1800京

たとえば、

負の数は要らないなあ。数の上限は1万くらいでいいや

と思ったら、16ビットで足りるので、その変数は以下のように宣言する。

unsigned short int x;

負の数も使う。数の上限は100万くらい欲しい。

と思ったら、32ビット欲しいのでその変数は以下のように宣言する。

signed long int y;

ただし(101/102教室のgcc環境の場合)、符号の有無と、長さを省略し ただ単に、int と宣言した場合、signed int とみ なされるので、上記のように長々と書く必要はなく、

int y;

だけで同じ意味になる。

一昔前は、longを使うとshortよりも計算時間がはるかにかかることがあったり したので、整数型に short を使うか long を使うかは大勝負だった。最近の 高速CPUでは、むしろ逆にlongよりもshortの方が処理時間がかかったりする ことがあるのでshortにするべきかどうか真剣に悩む機会は格段に減少した。

負の整数の表現方法

コンピュータの内部は2進数で整数を数えている。2進数を 10進数にする場合は、1の位から順に2のN乗を書けて行けば良い。 たとえば8桁(8ビット)の2進数 01000001 であれば、

272625 24 232221 20
128倍64倍32倍16倍 8倍4倍2倍1倍
0100 0001

64×1 + 1×1 = 65 となる。8ビットで表せる最大の2進数 11111111 は、

128×1+64×1+32×1+16×1+8×1+4×1+2×1+1 = 255

となる。では負の数はどうやって表すのだろう。整数型の上限下限の表 によると、負号あり8ビット整数 signed char は -128〜127 がその範囲である。 おおざっぱにいうと、符号なしで表せる0〜256個の数値を半分にすると、 0〜127の128個。これを負でない数の範囲にする。残った128個を負の数に 割り当てて-1〜 -128にしている。その方法を以下に示す。

まず、8ビットあるうちの先頭の1ビットを「負号を表すもの」とする。 先頭1ビットが0の場合は正の数、1の場合は負の数とする。

正の数

0xxx xxxx

負の数

1xxx xxxx

残り7ビットは、絶対値を表すものとするが、以下の規則を用いる。

正の数の場合は簡単で、たとえば、符号つきの2進数が、

0010 0110

は、2〜8ビット目の 00100110 を10進数に直して

32+4+2 = 38

が絶対値となり、符号つき2進数00100110 の値は38となる。

負の数の場合を考えよう。2進数 10100110 を10進数に直そう。

1010 0110

残る7ビットは 00100110 である。1と0を反転する。

010 0110
反転↓
101 1001

反転したものの数値は

64+16+8+1 = 89

これに1を足すと90となる。したがって、絶対値90にマイナスをつけた -90 が、 符号つき2進数10100110 の値となる。


本日の目次