TOP >> マニアックなプログラミング
トリッキーコードネット トリッキーなコード

【C言語】typedefと#defineの違い

C言語でのtypedefと#defineの違いについて書きます ^^;)

「 typedef, #define共に、変数型を別の任意の文字列で宣言できる。双方の挙動にさほど大きな違いはない 」
・・・と誤認されがちなのですが、実際の挙動は全く異なります。


まずは、以下のコードを見てください。
#include <stdio.h> #define char_ptr char * typedef char * char_ptr2; int main(void) { char_ptr a1, a2, a3; char_ptr2 b1, b2, b3; printf("%d\n", sizeof(a1)); printf("%d\n", sizeof(a2)); printf("%d\n", sizeof(a3)); printf("%d\n", sizeof(b1)); printf("%d\n", sizeof(b2)); printf("%d\n", sizeof(b3)); return 0; }
結果) C言語でのtypedefと#defineの違い 32bitCPU用のポインタのサイズは 4byte(=32bit)なので、全て4が表示されるはずじゃね?!Σ(゚Д゚) と驚いた人のみ、以下を読み進めて下さい。 (↑の結果が「至極当たり前じゃん」と理解している人は、もうこれ以上読み進める必要はありません ^^) さてさて、実は #defineとtypedefは、それぞれを解釈するプログラムが異なります。 #defineはプリプロセッサにより解釈され、typedefはコンパイラにより解釈されます。 周知の通りプリプロセッサとは、コンパイラがソースコードを解釈する前に、ソースコードへ文字列レベルの処理を加える プログラムです。 (だからこそプリプロセッサの事を、「前処理系」なんて表現を使ったりもします。) ファイルを読み込む #includeやら、コードを切り分ける #ifdef ... #endif、#defineによるマクロが有名ですね ^^ では、以下のコードをプリプロセッサが解釈したら、どんなソースコードが生成されるのでしょうか??
#define char_ptr char * char_ptr a1, a2, a3;
答えは次の通りです。
char * a1, a2, a3;
この場合、a1のみchar型のポインタとなり、a2, a3はchar型の変数となります。(詳細は、C言語の入門書を読んでください^^) その為、冒頭のコードの様な結果が表示された訳です。 一方 typedefの場合は、単純なソースコード文字列の置換ではなく、コンパイラが型情報を保持 しています。 (言うならば「変数型に別名でアクセスしている」状態です。) その為、デバッガで変数を追いかける際にも、typedefの定義は有効です。 (※ #defineを使った定義では、全く考えられない話) typedefの使い道としては、 例えば関数へchar型ポインタの配列を渡す場合等に、
typedef char * char_ptr; void func(char_ptr * aaa) {...
とすると、2重ポインタを渡すよりも、幾分コーディングが楽になったり、 構造体ポインタを多用する際などは、 struct _tagHOGE * aaa と書くよりも、間違いなく
typedef struct _tagHOGE { ... } hoge; hoge * aaa;
と書いた方が、間違いなくコードの可読性があがります。 そして何より、(上でも書きましたが)デバッグ時に型情報が維持される事が、とても有難いです。
トリッキーコードネット の TOPへ HOTNEWS の 総合TOPへ