typedefと#defineはcで同じですか?


回答:


122

番号。

#defineプリプロセッサトークンです。コンパイラ自体には決して表示されません。
typedefコンパイラトークンです。プリプロセッサはそれを気にしません。

どちらを使用しても同じ効果が得られますが、ニーズに応じて適切なものを使用することをお勧めします

#define MY_TYPE int
typedef int My_Type;

物事が「毛むくじゃら」になったら、適切なツールを使用してそれを正しくする

#define FX_TYPE void (*)(int)
typedef void (*stdfx)(int);

void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */

3
typedefの後、stdfxその型の有効なオブジェクトは、intを受け取り、値を返さない関数へのポインターです。
pmg

1
引数として関数ポインターのケースで#defineが失敗するのはなぜですか?
Allahjane 16

2
@Allahjane:拡張はvoid fx_def(void (*)(int) fx);; 正しい宣言はvoid fx_def(void (*fx)(int));です。
pmg 2017年

5
関数ポインタは、構文を放棄する準備ができている場合にのみ、マクロで実行できます#define FX_TYPE(f) void (*f)(int)。:あなたはその後、としてあなたの関数を宣言するだろうvoid fx_def(FX_TYPE(fx));
plafer

229

typedef変数と同じようにスコープ規則に従いますdefineが、コンパイル単位の最後まで(または一致するまでundef)有効です。

また、いくつかのものがで行うことができますtypedefで行うことができませんdefine
例えば:

typedef int* int_p1;
int_p1 a, b, c;  // a, b, c are all int pointers

#define int_p2 int*
int_p2 a, b, c;  // only the first is a pointer, because int_p2
                 // is replaced with int*, producing: int* a, b, c
                 // which should be read as: int *a, b, c
typedef int a10[10];
a10 a, b, c;  // create three 10-int arrays
typedef int (*func_p) (int);
func_p fp;  // func_p is a pointer to a function that
            // takes an int and returns an int

23

いいえ、同じではありません。例えば:

#define INTPTR int*
...
INTPTR a, b;

前処理後、その行は次のように拡張されます

int* a, b;

うまくいけば、あなたは問題を見るでしょう。aタイプのみになりますint *bはプレーンとして宣言されますint*型指定子ではなく、宣言子に関連付けられているため)。

それと対照的に

typedef int *INTPTR;
...
INTPTR a, b;

この場合、aおよびbはtypeになりint *ます。

関数や配列へのポインタなど、プリプロセッサマクロでエミュレートできないtypedefのクラス全体があります。

typedef int (*CALLBACK)(void);
typedef int *(*(*OBNOXIOUSFUNC)(void))[20]; 
...
CALLBACK aCallbackFunc;        // aCallbackFunc is a pointer to a function 
                               // returning int
OBNOXIOUSFUNC anObnoxiousFunc; // anObnoxiousFunc is a pointer to a function
                               // returning a pointer to a 20-element array
                               // of pointers to int

プリプロセッサマクロでそれを実行してみてください。


13

#defineはマクロを定義します。
typedefはタイプを定義します。

さて、ここでいくつかの違いがあります:

#defineあなたは、コンパイル時に使用できる定数を定義することができます。定数を#ifdefと共に使用して、コードのコンパイル方法を確認し、コンパイルパラメータに従って特定のコードを特殊化できます。#define
使用して、ミニチュアの検索および置換マクロ関数を宣言することもできます

typedefは、型にエイリアスを与えるために使用できます(おそらく#defineでも行うことができます)が、#define定数の検索と置換の性質により、より安全です。
さらに、typedef前方宣言を使用すると、使用する型を宣言できますが、書き込み中のファイルにはまだリンクされていません。


#defineの性質を見つけて置き換えるとはどういう意味ですか?、ありがとう
Mohamed El Shenawy 2015年

1
これは、コンパイルの前に、プリプロセッサがすべてのマクロを見つけて、それらを元の構文に置き換えることを意味します
Prince Vijay Pratap

「typedefを使用して型にエイリアスを与えることができます」これは私に感謝の意を説明しました。
Dave Voyles

8

プリプロセッサマクロ(「#define」)は、「検索と置換」の字句置換ツールです。それらはプログラミング言語に完全にとらわれず、何をしようとしているのか理解していません。あなたはそれらを美化したコピー/貼り付けの仕組みと考えることができます-時々それは便利ですが、注意して使用する必要があります。

Typedefは、型のエイリアスを作成できるC言語の機能です。これは、複雑な複合型(構造体や関数ポインターなど)を読みやすく扱いやすいものにするのに非常に役立ちます(C ++では、型をtypedefする必要がある場合さえあります)。

(3)の場合:可能であれば、常にプリプロセッサマクロよりも言語機能を優先する必要があります。したがって、型には常にtypedefを使用し、定数には定数値を使用してください。このようにして、コンパイラーは実際に有意義に対話できます。コンパイラは友だちであることを忘れないでください。そのため、できるだけ多く伝える必要があります。プリプロセッサマクロはによって正反対のことを隠して、コンパイラから、あなたのセマンティクスを。


型をtypedefする必要があるC ++の例を1つ教えてください。私はそれについて興味があります。
jyz 2013

@jyzuz:メンバー関数が関数ポインターの配列を返すようにしたい場合、またはそのような場合があります-タイプを綴ろうとすると、GCCは「typedefを使用する必要がある」と実際に言います。
Kerrek SB 2013

4

それらは非常に異なりますが、カスタムデータ型を実装するためによく使用されます(これは、この質問がすべてであると想定しているものです)。

pmgが言及した#defineように、コンパイラーがコードを認識する前にプリプロセッサーによって(カットアンドペースト操作のように)処理typedefされ、コンパイラーによって解釈されます。

(少なくともデータ型の定義に関して)主な違いの1つは、typedefより具体的な型チェックが可能になることです。例えば、

#define defType int
typedef int tdType

defType x;
tdType y;

ここで、コンパイラーは変数xをintと見なしますが、変数yはたまたまintと同じサイズの 'tdType'と呼ばれるデータ型と見なします。タイプdefTypeのパラメーターを取る関数を作成した場合、呼び出し元は通常のintを渡すことができ、コンパイラーは違いを認識できません。関数が代わりにtdType型のパラメーターを取った場合、コンパイラーは、関数呼び出し中に適切な型の変数が使用されるようにします。

また、一部のデバッガーはを処理する機能を備えています。これは、typedefすべてのカスタムタイプを基本プリミティブタイプとしてリストするよりもはるかに便利です(#define代わりにを使用した場合と同様)。


2

いいえ
。typedefは、型のエイリアスを作成するCキーワードです。
#defineはプリプロセッサ命令であり、コンパイル前にテキスト置換イベントを作成します。コンパイラがコードに到達すると、元の "#defined"ワードは存在しなくなります。#defineは主にマクロとグローバル定数に使用されます。


2
「ポインタ」という用語を使用すると、ここで混乱が生じる可能性があります。

同意した。それが私が戻ってMSDNにtypdefへのリンクを追加した理由です-将来の誰かがこの質問を使用してtypedefが何であるかを見つけるためにです。しかし、多分私はその言葉を変更する必要があります...
Traveling Tech Guy

2

AFAIK、いいえ。

typedef既存のデータ型に「エイリアス」を設定するのに役立ちます。たとえば typedef char chr;

#defineあるプリプロセッサマクロや一般的なパターンの置換を定義するために使用されるディレクティブ。たとえば #define MAX 100、すべての出現箇所MAXを100に置き換えます


0

上記のように、#defineとtypedefの間には重要な違いがあります。これについて考える正しい方法は、typedefを完全な「カプセル化された」型であると見なすことです。宣言した後は追加できません。

マクロの型名は他の型指定子で拡張できますが、typedefされた型名は拡張できません。

#define fruit int
unsigned fruit i;   // works fine

typedef int fruit;
unsigned fruit i;   // illegal

また、typedefされた名前は、宣言内のすべてのデクレーターのタイプを提供します。

#define fruit int *
fruit apple, banana;

マクロ展開後、2行目は次のようになります。

int *apple, banana;

Appleはintへのポインタですが、バナナはintです。比較において。次のようなtypedef:

typedef char *fruit;
fruit apple, banana;

リンゴとバナナの両方が同じであると宣言します。前面の名前は異なりますが、どちらもcharへのポインターです。


-1

誰もが上で言ったように、彼らは同じではありません。ほとんどの回答はtypedef、よりも有利であることを示しています#define。しかし、私はのプラスポイントを置いてみましょう#define
あなたのコードは非常に大きな多くのファイルに散在しているとき、それはより有効に活用するのです#define。読みやすさを向上させます。すべてのコードを前処理するだけで、変数の宣言自体の場所にある変数の実際の型定義を確認できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.