C++言語解説:1-2.基本データ型
2002-06-25

[概要] 変数、仮引数、変数の型、定数、エスケープシーケンス、基本となる演算子、キ
    ャストを扱います。

[構成]・基本データ型
     * 基本データ型は7種類
   ・変数の定義と種類
     * 変数の定義
     * ローカル変数
     * 仮引数
     * グローバル変数
   ・型修飾子
     * 型に対する修飾子
   ・定数
     * 文字定数
     * 数値定数
     * 文字列定数
     * エスケープシーケンス
   ・演算子
     * 算術演算子
     * インクリメントとデクリメント
     * 関係演算子と論理演算子
   ・型変換
     * 暗黙の型変換(char, int, float, double)
     * 暗黙の型変換(bool, int)
     * 明示的型変換(キャスト)

基本データ型

 基本データ型は7種類
 
  ・C++では変数を使用する際に定義が必要です。それはコンパイラに変数の扱うデータ
   の型(byte数)を示すためです。
  
  ・C++には単一(*1)のデータ/変数を示す型が7種類有ります。これらを基本データ型
   呼びます。しかしbit数や値の範囲はOSや環境により異なります。ここでは32bit環境
   での一例を示します。
   
   [Table1.C++の基本データ型(32bit環境の一例)]
   ┌───────────────────────────────────┐
    ┌────┬─────┬────────────────┐
    │ 型名 │32bit(Typ)│     値の範囲(Typ)     │
    ├────┼─────┼────────────────┤
    │char  │  8 bit │      -128〜127      │
    │wchar_t │ 16 bit │       0〜65,535     │
    │int   │ 32 bit │ -2,147,483,648〜2,147,483,647 │
    │float  │ 32 bit │    1.18E-38〜3.40E+38    │
    │double │ 64 bit │   2.23E-308〜1.79E+308   │
    │bool  │ ------ │      true, false     │
    │void  │ ------ │       値無し       │
    └────┴─────┴────────────────┘
   └───────────────────────────────────┘
  
  ・char型は8bitのASCII文字コードや、他の8bit値を表すのに使用します。文字を使用
   する場合、文字コードを表すためにシングルクォートで囲みます。
     char c_a = 'A';
  
  ・英語圏のように比較的文字種が少ない場合、文字データは上記char型のみで扱えま
   すが、日本語のように文字種が莫大な場合には無理です。そこでC++には多種の文字
   を扱うデータ型としてwchar_t型が追加されました。
  
  ・int型データは整数値を扱います。
  
  ・float型, double型小数点を必要とする小さな値、又は非常に大きな値を扱う場合
   に用います。float型とdouble型の違いは、扱える数値の範囲です。float/double型
   を扱う際には「丸め誤差/有効桁」(*2)の存在を忘れてはいけません。
   
  ・bool型true/false等のbool値を扱うものです。最近のC++(3rd Edition)で追加さ
   れました。
  
  ・void型は値を返さない関数の宣言に使用されます。


変数の定義と種類

 変数の定義
 
  ・変数の定義は
     型 変数リスト;
   のように、型に対する変数の識別子名(変数名)を羅列する形式で行います。変数名
   を複数記述する場合は、カンマで区切ります。

   [List1.変数定義の例]
   ┌───────────────────────────────────┐
    int i, j, k; //複数定義
    int i;    //1個だけ定義
    char c;   //char型定義
   └───────────────────────────────────┘
  
  ・識別子名は型に関係なく設定でき、1024文字までが有効です(1024文字中のどこかが
   異なれば違う名前と見なす)。
  
  ・変数には、以下の3種類があります。
     ローカル変数(local variable)
     仮引数(parameter)
     グローバル変数(global variable)


 ローカル変数
 
  ・ローカル変数は関数内部で定義される変数です。定義した関数の内部でのみ有効で
   関数の実行が終了すると、保持していた値は失われます。
  
  ・関数が呼び出される度に自動的に変数が生成されることから、自動変数(automatic
   varibale)
とも呼ばれています。

   [List2.ローカル変数の例]
   ┌───────────────────────────────────┐
    #include <iostream>
    using namespace std;
    
    void SubFunc();
    
    int main()
    {
      int a;   //main()の中だけで有効
       :
      SubFunc(); //SubFunc()呼び出し
       :
      return 0;
    }
    
    void SubFunc()
    {
      int a;   //SubFunc()の中だけで有効
       :
       :
      return;
    }
   └───────────────────────────────────┘


 仮引数
 
  ・関数に値を渡す場合、それらを受け取るための変数を用意する必要があります。こ
   の変数は仮引数(formal parameter)と呼ばれます。
  
  ・仮引数は、ローカル変数と同様に関数の呼び出し時に生成され、関数が終了すると
   値が破棄
されます。
  
  ・仮引数とローカル変数の違いは、生成時に初期値が必ず渡されるという点です。

   [List3.仮引数の例]
   ┌───────────────────────────────────┐
    #include <iostream>
    using namespace std;
    
    void SubFunc(int a);
    
    int main()
    {
      int a;     //ローカル変数
       :
      SubFunc(a);   //SubFunc()呼び出し
       :
      return 0;
    }
    
    void SubFunc(int b) //bは仮引数
    {          //初期値はmain()のaの値がコピーされる
      cout << b;
       :
       :
      return;
    }
   └───────────────────────────────────┘


 グローバル変数

  ・ローカル変数や仮引数と異なり、プログラム実行中に常に存在し、値を保持し続け
   る
変数を、グローバル変数(global variable)と呼びます。
  
  ・グローバル変数を定義するには、全ての関数の外側で変数の定義を行います。一般
   的にはプログラムの先頭で定義します。
  
  ・グローバル変数は常に存在するので、全ての関数から、つまりプログラム全体から
   アクセスすることができます。ただし、変数は定義しないと使用できないので「プ
   ログラムの先頭で定義」
することは重要です。

   [List4.グローバル変数の例]
   ┌───────────────────────────────────┐
    #include <iostream>
    using namespace std;
    
    void SubFunc1();
    void SubFunc2();
    
    int sum; //グローバル変数定義
    
    int main()
    {
      sum = 10;
      cout << "1st sum = " << sum << endl;
      
      SubFunc1();
      cout << "2nd sum = " << sum << endl;

      SubFunc2();
      cout << "4th sum = " << sum << endl;
      
      return 0;
    }
    
    void SubFunc1()
    {
      sum = 20; //ここはグローバルのsum
      return;
    }

    void SubFunc2()
    {
      int sum = 30; //ローカル変数のsumを定義
      
      cout << "3rd sum = " << sum << endl;
      return;
    }
   └───────────────────────────────────┘
   ┌───────────────────────────────────┐
    [出力結果]
    1st sum = 10
    2nd sum = 20
    3rd sum = 30 //SubFunc2内のローカル
    4th sum = 20 //SybFunc2のローカルsumに影響を受けない
   └───────────────────────────────────┘
  
  ・List4の結果からわかるように、グローバル変数と同名のローカル変数が定義されて
   いる場合
、その関数内において同名変数へのアクセスすると、ローカル変数を参照
   することになります。この点は要注意です。
  
  ・一見非常に便利なグローバル変数ですが、「どこからでも参照できる」という強力
   な性質故に、害になるケースが多いことにも注意が必要
です。特に多人数でプログ
   ラムを行っている場合、自分が期待している値をグローバル変数が持っているとは
   限らなくなるからです。
   

型修飾子

 型に対する修飾子
 
  ・データの基本型であるint, char, doubleには、型の前に修飾子(modifier)を付ける
   ことができます。修飾子には
     signed, unsigned, long, short
   の4種類があります。
  
  ・Table2に基本型と修飾子の組合せを示します。
  
   [Table2.基本型と修飾子の組合せ]
   ┌───────────────────────────────────┐
     (1)サイズ系修飾子
     ┌────┬─────┬─────┐
     │    │ short  │  long  │
     ├────┼─────┼─────┤
     │ char  │  ×  │  ×  │
     │ int  │  ○  │  ○  │
     │ double │  ×  │  ○  │
     └────┴─────┴─────┘
    
     (2)サイズ+符号系修飾子
     ┌───────┬─────┬─────┬────┐
     │       │ signed │ unsigned │ 省略時 │
     ├───────┼─────┼─────┼────┤
     │ char     │  ○  │  ○  │ signed │
     │ int     │  ○  │  ○  │ signed │
     │ short int  │  ○  │  ○  │ signed │
     │ long int   │  ○  │  ○  │ signed │
     │ double    │  ×  │  ×  │ ---- │
     │ long double │  ×  │  ×  │ ---- │
     └───────┴─────┴─────┴────┘
   └───────────────────────────────────┘
   
  ・大抵の16bitOS環境では
    16bit : short int = int
    32bit : long int
   となります。一方、大抵の32bitOS環境では
    16bit : short int
    32bit : long int = int
   です。(ただし、使用環境での確認は必要です)。
  
  
定数
 
 文字定数
 
  ・文字型には、charとw_charがあります。char型に定数を割り当てる場合は先も書き
   ましたがシングルクォートで囲みます。
     char c_a;
     c_a = 'A';
 
  ・ワイド文字(wchar_t型)の定数を指定するときは、文字の前にLを付けます。
     wchar_t wc_a;
     wc_a = L'A';
 
 
 数値定数
 
  ・小数点の無い数値は整数定数として扱われますが、整数には
    int / long int / unsigned int
   があり、数値の大きさによりコンパイラは適当な型を割り当てます。しかし、整数
   定数の型を明記したい場合は以下のように表現します。
     int     : 1 10 -123
     long int   : 3000L -60L
     unsigned int : 500U -128U
  
  ・浮動小数点にはfloatとdouble型があります。浮動小数点型についてもコンパイラは
   適当な型を割り当てますが、必要であれば型を明記できます。
     float    : 123.55F 1.56e-4F
     double   : 10.25 803.64 -12.5
     long double : 10005.6L
  
  ・16進数と8進数で定数を表記することもできます。16進数は0xで始め、8進数は0で始
   めます。
     int hex = 0xF1A; //16進数
     int oct = 016  //8進数


 文字列定数
 
  ・文字列(string)データは、文字の集まりをダブルクォートで囲んだものです。
    (例) "this is a string"
  
  ・Cには文字列型データは無く、char型データの集まりとして扱います。文字列につい
   ては、1-4(配列と文字列の基本)で説明します。
  
  ・C++には標準クラスライブラリでstring型があります。これについては第2編(オブジ
   ェクト指向プログラミング)に入ってから説明します。


 エスケープシーケンス
 
  ・C/C++では特別な意味を持つ文字があります。例えば「改行」や「タブ」等がそうで
   す。これらの特別な文字は「\マーク+記号」で表され、エスケープシーケンス
   (escape sequence)
と呼ばれます。
  
  ・Table3にエスケープシーケンスの一覧を示します。

   [Table3.エスケープシーケンス一覧]
   ┌───────────────────────────────────┐
    |コード|      内容      |
    +------+----------------------------+
    | \b  | バックスペース       |
    | \f  | 改ページ(フォームフィード) |
    | \n  | 改行(ニューライン)     |
    | \r  | 復帰(キャリッジリターン)  |
    | \t  | 水平方向タブ        |
    | \v  | 垂直方向タブ        |
    | \"  | ダブルクォート       |
    | \'  | シングルクォート      |
    | \\  | \記号           |
    | \a  | 警告音(ビープ)       |
    | \?  | ?記号           |
    | \oo | 8進定数 oo        |
    | \xhh | 16進定数 hh        |
   └───────────────────────────────────┘
   
  ・8進定数と16進定数については、その数値コードで表される文字を意味します。
   List5の例を見た方がわかりやすいでしょう。
   
   [List5.エスケープシーケンス使用例:特に16進/8進表記]
   ┌───────────────────────────────────┐
    #include <iostream>
    using namespace std;
    
    int main()
    {
      cout << "char \'0\':" << '0' << "\n";
      cout << "int \'0\':" << (int)'0' << "\n";
      cout << "char 48 :" << (char)48 << "\n";
      
      cout << "\'\\x30\' :" << '\x30' << " : 16進 " << "\n";
      cout << "\'\\60\'  :" << '\60' << " : 8進 " << "\n";
      
      return 0;
    }
   └───────────────────────────────────┘
   ┌───────────────────────────────────┐
    [実行結果]
     char '0':0
     int '0':48
     char 48 :0
     '\x30' :0 : 16進
     '\60'  :0 : 8進
   └───────────────────────────────────┘
   
   
演算子

 算術演算子
 
  ・四則演算子は当然サポートされています(+, -, /, *)。整数同士の除算では、余り
   が切り捨てられます。

   
  ・他の整数(int系)に関する演算子として剰余演算子(%)があります。剰余演算子は余
   りを示します。例えば、10 % 3の結果は 1 となります。

  
 インクリメントとデクリメント
 
  ・1を加える操作をインクリメント(increment)、1を減じる操作をデクリメント
   (decrement)と呼びます。C/C++には、この操作を行う演算子があります。
     ++ : インクリメント
     -- : デクリメント
  
  ・インクリメントとデクリメント演算子には前置き(prefix)と後置き(postfix)があり
   ます。前置きの場合、ステートメントの演算子優先順位として括弧()の次にインク
   リメント/デクリメントが実行
され、値が変化したオペランドで式が評価されます。
  
  ・一方後置きの場合、インクリメント/デクリメントはステートメント実行後に行われ
   ます。
     (例) int a=10;        | int a=10;
        b = ++a; //前置き b=11 | b = a++; //後置き b=10
  
  ・インクリメント/デクリメントは他の則/剰余演算子よりも実行優先度が高くなりま
   すが、括弧()よりは優先度が下がります。よって優先度を制御したい場合は括弧()
   を利用
します。


 関係演算子と論理演算子
 
  ・C/C++の関係演算子(relational operator)ですが
     >, >=, <, <=   (=が付いたものは以上/以下を意味する)
   の4種類については説明不要でしょう。表記が特殊なものとして
     == : 等しい
     != : 等しくない
   があります。関係演算子の演算結果はbool型でtrue又はfalseとなります。
  
  ・C/C++の論理演算子(logical operator)は以下の3種です。
     && : AND (2項演算子)
     || : OR (2項演算子)
     !  : NOT (単項演算子)
   これらはbool型オペランドに対する演算子です。演算結果もbool型です。
     (例) (a>b) && (d<=a)
        true   false → false
        false  true  → false
        true   true  → true
       

型変換

 暗黙の型変換(char, int, float, double)
 
  ・コンパイラは異なる型同士の演算式がある場合、式中の全てのオペランドを上位(最
   も大きいデータ範囲を取り得る)の型に変換
します。
  
  ・データ型を上位から並べると以下になります
    double
    float
    int
    char
  
  ・例えば、intとfloatの演算式があった場合、式中の全てのオペレータはfloatに変換
   された状態でコンパイルされます。
 
 
 暗黙の型変換(bool, int)
 
  ・bool型とint型は状況に応じて相互に変換されます。
     bool   int
     true ─→ 1
     true ←─ 0以外
     false ←→ 0
  
  ・例えば、次回説明予定のif文により条件判断では、int演算式がbool型へ変換されま
   す。コンパイラ側で自動変換されるため
     true : 非0を意味する
     false : 0を意味する
   の認識で十分です。
   

 明示的型変換(キャスト)
 
  ・異なる型同士の演算については暗黙の型変換があるのですが、明示的に型を指定
   ることもできます。これがキャスト(cast)です。
  
  ・例えば、整数同士の除算では結果が浮動小数点になるケースがありますが、そのま
   まだと整数の演算結果しか得られません。そこでキャストを使用し、型としてfloat
   を指定するなどの利用方法があります。

  
  ・キャストは以下のように、式の前に適用したい型を括弧で囲んで置きます。
    (例) int a=3;
       int b=2;
       cout << (float)(a/b); //1.5はfloatで表現
  
  ・ただし、キャストは言い方を変えれば「コンパイラ」をだます手法でもあり、キャ
   ストを行うことは、コンパイラに生成「させた」コードに対しプログラマがきちん
   と責任を持つ必要があることを意味します。

  
  ・よってキャストはできるだけ避けるようなプログラミングを行うべきだと筆者は考
   えています。


(*1)構造体やクラスは複数データの集合体ですが、C++はそれらも型として扱えます。構造
  体とクラスについては以後の教育で説明します。

(*2)コンピュータは2進数でデータを扱うので、10進数で問題ない数値も、2進数では表現
  できないケースがあります。例えば 0.05 という数値を2進数で表すと
    0.0000111.....
  のように無限小数になってしまいます。このようなデータを限られた桁(有効桁)で表
  すために下位の桁は削除されます。値が大きい場合も同様で、仮数部で表せない桁は
  切り落とされます。

[Revision Table]
 |Revision |Date    |Comments
 |----------|-----------|-----------------------------------------------------
 |1.00   |2002-06-25 |初版
 |1.01   |2002-06-30 |語句修正
 |1.02   |2002-07-30 |語句修正
 |1.03   |2002-08-15 |リンク追加
[end]
Copyright(C) 2002 Altmo