コンピュータで扱うデータには「型」がある。我々人間も,扱うデータが数値なのか文字なのか,はたまた映像なのかくらいは意識するけれど,コンピュータでいう型はそれよりもっとややこしそうだ。
「型」について調べていくうちに,人間の脳ミソで展開される情報とコンピュータのメモリーの中で扱われる「データ」との決定的な違いがわかってきた。
調査結果は非常に膨大なものとなったため,今回は「符号付き/符号なし」と「桁あふれ」の問題を中心に報告する。
変数にも,定数にも,処理にも,型がある
プログラミングに「型」は付きものだ。一般には「データ型」と言われる。コンピュータで扱うデータには必ず値と型がある。データ型というと変数だけが対象となるような気がするけれど,そうでないことは読者ならご存じのはず。定数*1にも型がある。
Cでは,型を明示しない整数の定数はint型とされる。int型以外のデータと演算する場合には,キャストの必要がある。
float x, y;
…
x = (float)1000 * y; /* 定数'1000'をfloat型にキャスト */
定数の型を明示する場合には,後ろに型を示す記号を付加する*2。例えばlong型なら“L”を使う(小文字でも可)。
/* long型の整数'1000'を記号定数'__MAX'として定義 */
#define __MAX 1000L;
Visual Basic(VB)ではConst命令を使って*3次のように定数を宣言する。
Const __MAX = 1000
このVBの例でも型は暗黙のうちに決まる(上の例ならInteger)。が,宣言セクションで“Option Strict On”として明示的な型変換を強制するよう設定すれば,以下のようにAs句を使って定数の型を明示しなければならなくなる。
Const __MAX As Integer = 1000
データだけではなく,コード(処理)にも型がある。関数やプロシジャの型だ。VBでは値を返すFunctionプロシジャが型を持ち,値を返さないSubプロシジャは型を持たない。それぞれの宣言は,以下のように異なっている。
Function GetMaxNum () As Integer ――値を返す
Sub ViewFileName() ――値を返さない
Cの場合は,基本的にすべての関数が型を持つ。関数の宣言では,必ず戻り値の型を示さなければならない。何の値も返さない関数も,voidという「型がないことを示す型」をあてる。
int getmaxnum(); ――値を返す
void viewfilename(); ――値を返さない
プロシジャや関数の型というのは,それらが返す値の型である。だから,やはり「値=データの型」なのだ。
誰がどこで型を決めているのか?
さて,データの型とは何なのだろう? この疑問を突き詰めていくと,コンピュータと人間との違いが見えてくる。
「データ型って何?」と問われれば,「そんなの決まってるよ。整数とか小数とか文字列とか…」と,声が聞こえてきそうだ。もちろんそれはわかっているのだが,では,「あるデータが整数(例えばVBのInteger)である」というのは,一体どういう状況なのだろう?
マイクロソフトのオンライン・ドキュメントには,VBのInteger型について以下のように記されている。
整数型(Integer)の変数は,32ビット(4バイト)の符号付き整数として格納され,-2,147,483,648~2,147,483,647の範囲の値をとります。 |
まぁ,そうゆうことだ…と,ここで納得してはいけない。確かに書いてある通りなのだが,上のようなことはどこでどのように規定されているのだろうか? もちろん処理系(この場合ならVB)が規定しているわけだが,どんな仕組みで,例えば「Num As Integer」という宣言を「Numという名前の変数には-2,147,483,648 ~ 2,147,483,647の範囲の符号付き整数を格納する」という処理に対応させているのだろう?