typedefの利用

typedef宣言

キーワードtypedef を用いて、既存のデータ型に新しい名前をつけることができる。

typedef 既存の型名 新しい型名;


typedef で用いる構文は、「普通の変数宣言の先頭にtypedef と書けば、変数ではなく型の宣言となる。」と覚えておけばよい。

たとえば・・

        int i;        // これは、int型の変数 i の作成
typedef int INTEGER;  // これは、INTEGER という新しい型のtypedef宣言


INTEGER foo;          // 先にtypedefした INTEGER型の変数 foo の宣言

特に #define マクロとごっちゃになってしまう初心者は、ここでしっかりと覚えなおしておくこと。(typedef はマクロではないので,行末には必ずセミコロン(;) が必要.)

typedef の利用法 1 −構造体に名前をつける

構造体の宣言とその作成方法は以下のような方法であった。

// 構造体の宣言
struct employee {
    char name[12];
    double hours;
    int wage;
};
struct employee yamada;   // struct employee型の変数 yamada を作成

構造体 employee を作成するには、そのたびに struct employee とタイプしなければならない。(注1)typedef を使用して、この構造体を EMPLOYEE という新しい型名をつけることができる。(注2

typedef struct employee {  //この場合、タグ(employee)は書いても書かなくてもよい
    char name[12];
    double hours;
    int wage;
} EMPLOYEE;
EMPLOYEE yamada;   // EMPLOYEE 型の変数 yamada を作成

 

typedefの利用法 2 −ポインタの作成を容易にする

intを指すポインタを宣言するには int *p; もしくは int* p; と記述する。スペースはアスタリスク(*)の左右どちらにいれてもよいし、いれなくてもよく、単に見た目の問題である。
int* p; と書いたほうが、「『intを指すポインタ』という型の変数 p」 という風に見える、という理由で、こちらの書き方を好む人も多い。

ここで問題となるのは、intを指すポインタとして、p1 と p2 を一緒に宣言しようとする場合である。int* p1, p2; と記述すると、int を指すポインタ(int*)の変数 p1 と、int型 (int) の p2 が作成されてしまう。
期待通りに変数を作成するには、 int *p1, *p2; と宣言する必要がある。

ポインタを頻繁に扱うプログラムにおいては、ポインタ型として新しい型を typedef 宣言しておくのが便利である。

typedef int *PINT;   // 「intを指すポインタ」型として PINT を宣言
PINT p1, p2;         // 期待通りに「intを指すポインタ」のp1 と p2 を作成できる

ポインタ型の typedef 宣言はすこし奇妙に見えるかもしれないが、先に書いた、「普通の変数宣言の先頭にtypedef と書けば、変数ではなく型の宣言となる。」というルールを思い出してもらえれば、さほど理解に苦しむことはないと思う。(int *PINT; と書けば、intを指すポインタの PINT という変数ができる。この前に typedef と書けば、それが PINT という新しい型の宣言になる。)
このように、ポインタに対して新しい型名をつけることにより、ポインタの宣言を見やすく、間違いを減らすことができる。
特に、ポインタの配列を使用するときなどには、 PINT pArray[10]; と書けばすむようになり、正しい記述が int* p[10];  だったか int (*p)[10]; だったかなどと悩む必要もなくなる。

int p, *q; と書くと、int型の変数 p と、intを指すポインタの q が作成されることは、先にお話したとおりである。この先頭に typedef と書くと、二つの型を同時に typedef 宣言することができる。

typedef int INT, *PINT;

INT  i;  // INT型(intと同じ)の変数 i の作成
PINT p;  // PINT型 (INTを指すポインタ)の変数 p の作成。 int* p; と同じ

typedefの利用法 3 −構造体と、それを指すポインタ型を同時に宣言

利用法2 の最後の形を、構造体に当てはめると以下のようになる。

// 構造体 CELL型と、CELLを指すポインタ型の
// の PCELL型 を同時に宣言
typedef struct cell {
    char string[10];
    struct cell *next;
} CELL, *PCELL;


PCELL pCell; //pCellは CELL を指すポインタ CELL* pCell; と同じ意味

上記は、リストのセルをあらわす構造体として CELL型を、CELLを指すポインタ型として PCELL型を、同時にtyepdef 宣言した例である。
このような typedef 宣言は非常に便利であり、よく利用されるので、C言語のイディオムとしてしっかり覚えておくとよい。


注1)C++の場合には、 タグ名をそのまま型名として利用できるので employee yamada; とだけ記述できる。

注2) タグ名、メンバー名、typedefによる型名には、別々の名前空間が利用される。このため、これらに同じ名前を使用することも可能であるが、混乱を招くことが多いので避けたほうがよい。