私たちは普段の生活の中で、数値を10進数で認識しています。それがもっとも扱いやすくて、効率が良いからです。
コンピュータにとっては2進数が扱いやすいため、コンピュータ内部では2進数で数値を扱っています。コンピュータが内部でどのように値を扱っているか知っておくと、プログラミングをする上でとても都合がよくなりますので、ここで整理しておきます。
1けたの2進数を扱える領域の単位をビットと呼びます。値は、「0(零)」か「0(零)以外」かのいずれかです。「0以外」だと見づらいので、たいていは「1」と書きます。
ビットの値を0から0以外にすることを、「ビットをセットする」といいます。また、いくつかのビットをまとめてバイトと呼びます。
いくつのビットをまとめてバイトと呼ぶのかはコンパイラによって異なりますが、現在使われている環境のほとんどが8個のビットをまとめて1バイトとしています。つまり8ビットは1バイトです。
2進数の8けたは、16進数の2けたで表現できます。つまり、1バイトを16進数の2けたで表現できます。例えば、2進数の「10100101」は、16進数の「A5」です。ここでは2進数や16進数について細かく説明しませんが、ぜひマスターしておきましょう。
さて、先ほど型の大きさについて説明しましたが、GCCやVisual C++では、unsigned char型の表現できる値の範囲は255まででした。10進数の255は、16進数のFFです。つまり、ちょうど8ビットで表すことのできる大きさになっています。
同じように、unsigned short int型は16ビット、unsigned int型とunsigned long int型は32ビット、unsigned long long int型は64ビットの領域を持っていることが分かります。
型がどれくらいの大きさを持っているかは、プログラムの中で調べられます。Sample1.cの8行目を次のように変更して実行してみましょう。
8 printf("sum : %d\n", sizeof(sum));
sum : 4
実行結果の4は、sumという変数が4バイトの大きさを持っていることを表しています。sumはint型でしたから、この環境ではint型が4バイト、つまり32ビットということなります。
あるいは、「sizeof(sum)」のように変数名ではなく、「sizeof(int)」のように型を書くこともできます。このようにsizeofを利用すると、その変数や型の大きさが分かります。
なお、sizeofの対象が型以外のときは、後ろのカッコを省略できますので、「sizeof(sum)」の代わりに「sizeof sum」と書くこともできます。ほかの型についても大きさを確認してみると理解が早いでしょう。
ところで、intなどの型の大きさはコンパイラによって異なりますが、厳密に型の大きさを特定したい場合もあります。複数の環境でコンパイルするときに大きさが異なってほしくない場合や、ビットやバイトの並びとして整数を扱いたい場合などが考えられます。
C99以前は、コンパイラ独自の拡張としてこのような要求に対応していましたが、C99では次の型を用意しています(*4)。
【*4】 これらの型を使うには、stdint.hヘッダをインクルードします。比較的新しいコンパイラはサポートしている場合が多いのですが、どの環境でも必ず使えるというわけではありませんので、詳しくはコンパイラの仕様を確認してください
実際にはこれらの型を使用するケースは少なく、システム(オペレーティングシステムなど)が提供する型を使うことが多いでしょう。初めはどの方を使ったらいいか戸惑うかもしれませんが、周りの方のコードを読んで徐々に慣れていき、必要に応じて使い分けられるようになりましょう。
ここまで変数について見てきました。変数はプログラムの実行中に値を変えられます。実は、値にも型があります。
変数と違って値は、その表現するものを後から変更できません。例えば、Sample1.cでは、「30」や「70」という値が出てきました。これは10進数の30、および70を表していて、それを変更することはできません。これを定数と呼びます。
定数では、値の書き方によって型が決まります。次に、整数定数、浮動小数点定数、文字定数、文字列リテラルの書き方を説明します。
Sample1.cにでてくる「30」や「70」を定数と呼ぶと説明しました。一般的にプログラミング言語では、こういった値をリテラルと呼ぶことが多いのですが、JIS Cでは、このようにソースコードへ直接記述する値を定数と呼んでいます。
リテラル(literal)は、「文字どおり」という意味ですから、「記述したとおりの値」というニュアンスになりますが、JIS Cでは、この値は変わらないということに注目をして、定数という用語を使っているのでしょう。
整数には、10進数のほかに、8進数と16進数で書く方法があります。1〜9の数字で始めると10進数になります。0で始めると8進数、0xあるいは0Xで始めると16進数になります。
16進数の場合、大文字小文字を区別しませんので、AからFであれば大文字でも小文字でも、混在させてもかまいません。しかし一般的には、16進数の最初の0xは小文字で書き、それに続く文字は大文字小文字のいずれかで統一することが多いので、それに従うのが良いでしょう。
値の終わりに接尾語を付けることで、その値の型を指定できます。接尾語にはU、L、LLの3種類、およびその組み合わせがあり、それぞれ次のように解釈されます。
ややこしいと思われるかもしれませんが、基本的には、省略したらint、Uが付いたらunsigned、Lが付いたらlong、LLが付いたらlong longで、その中に収まらなければより大きな型と解釈されるということになります。
ただし、接尾語なし、あるいはUが付かない場合で、しかも10進数ではなく8進数あるいは16進数を用いると、符号なし整数も候補になります。ルールが多いと覚えるのが大変なのですが、16進数で定数値を書くときには符号なし整数型として扱うことが多いので、この方が直感的に使える仕様なのです。
浮動小数点定数の書き方は、整数定数の書き方と似ていますが、少し違います。
例えば、5.0e-2と書けば、5.0×(10のマイナス2乗)、つまり0.05となります。指数部は省略できますので、単に0.05と書くこともできます。
また、C99からは16進数でも浮動小数点定数を書けるようになりました。書き方は次のとおりです。
普段は10進数で浮動小数点数を書くことが多いと思いますが、精度を厳密に制御したいときには16進数で書くことが必要になるかもしれません。
文字定数は“'”(一重引用符/シングルクオーテーション)で囲われた文字です。引用符の中に書けるのは、1バイトで表すことができる文字が1つだけです。
コンピュータの中では、文字も数値で扱っています。1つの文字を何バイトで表わすことができるのかは、その環境が利用している文字と数値の対応表(文字コード)によって変わります。しかし、多くの環境において1バイトで表わすことができる文字といえば、数字、アルファベットと、いくつかの記号だけです。特にPCにおいては、ほとんどの環境でASCIIという文字コードにある文字が使えます。
文字のAを文字定数で表すには「'A'」と書きます。文字定数は、対応する整数定数に変換されて処理されます。つまり、文字がASCIIとして処理される環境で「'A'」と書けば、それは「0x41」(16進数の41)と書いたことと同じになります。
変換された後の数値をそのまま書くこともできます。そのためには一重引用符の中で\(円記号)に続けて8進数で書くか、\xに続けて16進数で書きます。例えば、Aの変換された整数値である0x41を表したければ、「'\101'」あるいは「'\x41'」と書きます。
詳細な説明はしませんが、歴史的な経緯により、円記号“\”は何かと扱いが難しい文字です。ここでは日本語Windows環境を前提としているので、円記号と書きましたが、環境によっては、バックスラッシュで表示される場合もあります。
「¥\」と書いたHTMLを用意してWebブラウザでどのように表示されるか確認してみるとよいでしょう。筆者のWindows環境では「円記号が2つ」で、Mac OS X環境では「円記号とバックスラッシュ」でした。
Mac OS X では円記号ではなくバックスラッシュを入力する必要があります。そんなときは、「optionキー(alt) + \」としてみましょう。バックスラッシュが入力できます。
一重引用符の中にはどのような文字でも書けますが、例外として、'(一重引用符)と\(円記号)はそのまま書けません。これらの文字を書くときには「'\''」「'\\'」と書く必要があります。
また、特別な意味を持つ文字がいくつかあります。比較的よく使われるものを3つ紹介します。
文字の並びを文字列と呼び、文字列の定数のことを文字列リテラルと呼びます。
文字列リテラルは、“"”(二重引用符/ダブルクオーテーション)で囲われた文字の並びです。Sample1.cでは、表示する文字列の書式を指定している8行目で使用しています。
文字列リテラルの中には、文字定数と同じ文字が書けます。'A'のような一般に文字として扱われる文字だけではなく、円記号で始まる8進数および16進数による文字の数値表記や、'\n'のような特別な意味を持つ文字が書けます。
ただし、"(二重引用符)をそのまま書いてしまうと文字列リテラルの終了と区別が付きませんので、「\"」のように円記号に続けて書く必要があります。
これまで説明したように、Cには初めから多くの型が定義されていますが、プログラマがその型の新しい型名を定義することもできます。
新しい型名を定義するときには、typedefを使用します。typedefは「typedef 型 新しい型名」のように使います。こうすることで、新しい型名は、元となった型と同じように使うことができます。
typedef int T; T x;
このコードでは、Tという新しい型名を宣言しています。Tはint型を表していますので、変数xはint型になります。
typedefがよく使われる例として、1バイトを表す型名があります。Cには1バイトを表す型はありません。unsigned char型の大きさは1バイトですが、そのunsigned charという名前からバイト型であることは直接判断できません。
そのため、1バイトの大きさを持つ型ということで、「typedef unsigned char BYTE;」のように宣言することがよく行われます。
typedefの機能はシンプルですが、よく使われますのでぜひ覚えておいてください。
今回はたくさんの型を紹介しましたが、Cに用意されている型はこれだけではありません。しかし、大事なのは「型の種類を覚えること」ではなく、「いま、どの型を使用しているのかを意識してプログラムを記述できること」です。常にそのことを意識しながらプログラミングしていきましょう。
Copyright © ITmedia, Inc. All Rights Reserved.