typedef と define の違いを理解しようとしています。SO に関するこの前の質問には、特に良い投稿がたくさんありますが、その投稿が理解できません
#define
はプリプロセッサ トークンです。コンパイラ自体はそれを認識しません。
typedef
はコンパイラ トークンです。プリプロセッサはそれを気にしません。
どなたか、これをもう少し詳しく説明していただけないでしょうか。ここでのプリプロセッサという用語と混同しています。
typedef と define の違いを理解しようとしています。SO に関するこの前の質問には、特に良い投稿がたくさんありますが、その投稿が理解できません
#define
はプリプロセッサ トークンです。コンパイラ自体はそれを認識しません。
typedef
はコンパイラ トークンです。プリプロセッサはそれを気にしません。
どなたか、これをもう少し詳しく説明していただけないでしょうか。ここでのプリプロセッサという用語と混同しています。
プリプロセッサは、コンパイラの前に実行され、基本的にテキスト置換を実行するプログラムです。あなたが書くとき:
#define X 10
int main()
{
int x = X;
}
プリプロセッサはそのファイルを入力として受け取り、それを実行して出力します。
int main()
{
int x = 10;
}
そして、コンパイラは前処理された出力を処理します。
typedef
一方、コンパイラが理解する構造です。あなたが書くとき:
typedef unsigned int uint_32;
コンパイラは、uint32
が実際には のエイリアスであることを認識していunsigned int
ます。このエイリアスはコンパイラ自体によって処理され、単純なテキスト置換よりも少し多くのロジックが含まれます。これは、簡単な例で明らかになります。
typedef int my_int;
int main()
{
unsigned my_int x; // oops, error
}
単純なテキスト置換メカニズム (プリプロセッサのようなもの) である場合typedef
、それは機能しますが、許可されておらず、コンパイルに失敗します。
プリプロセッサは、コンパイルが開始される前に発生するフェーズです。置換する特定のマクロとシンボルを読み取ります。通常は 1 ~ 2 回のパスです。ソース ファイル全体をスキャンし、マクロを置換または展開するシンボル テーブルを生成します。
すべての置換が完了すると、構文アナライザーは、ソース ファイルの字句解析、抽象構文ツリーの生成、コードの生成、ライブラリのリンク、および実行可能ファイル/バイナリの生成を引き継ぎます。
C/C++/ObjC プリプロセッサ ディレクティブでは、「#」で始まり、その後に「define」、「ifdef」、「ifndef」、「elif」、「if」、「endif」などのディレクティブ名が続きます。
前処理の前に:
#define TEXT_MACRO(x) L##x
#define RETURN return(0)
int main(int argc, char *argv[])
{
static wchar_t buffer[] = TEXT_MACRO("HELLO WORLD");
RETURN ;
}
前処理後:
int main(int argc, char *argv[])
{
static wchar_t buffer[] = L"HELLO WORLD";
return (0);
}
私の記憶が正しければ、Kernighan と Ritchie による本「The C Programming Language」第 2 版には、独自の PREPROCESSOR の作成方法とその仕組みが示されている例があります。また、Plan9 C コンパイラは、2 つのプロセス (コンパイルと前処理) を分離しました。その中で独自の PREPROCESSOR を使用できるようにします。
複数言語用の興味深いプリプロセッサと自分のプリプロセッサを書く をチェックしてください。これらのプログラムの入力と出力を見ると、プリプロセッサが実際に何であるかをより深く理解できます。
もう 1 つの小さな秘密: プリプロセッサがあれば、C をラテン語/ドイツ語/スペイン語でコーディングできます :)
C および C++ プリプロセッサは、非常に早い段階で発生するコンパイルの論理フェーズです。プリプロセッサは、 で指定されたヘッダー ファイルのテキストを含め、ファイルの一部 ( 、、、バリアントおよび)#include
を条件付きで除外し、マクロ置換を行うことによって、ソース ファイルを翻訳単位に変換します。マクロは;を介して定義されます。マクロは、ソースをスキャンするプリプロセッサによって検出できます。#if
#elif
#else
#endif
#ifdef
#ifndef
#define
プリプロセッサは、で始まるほとんどの行を削除します(ソースがどこから来たかをコンパイラに伝えるために、ディレクティブと独自の省略形#
のみを残します)。次に、適切なコンパイラが前処理の結果を確認し、定義されているソース コードをコンパイルします。#line
#line
通常、プリプロセッサは単語を変更しませんtypedef
。非常識なプログラマがマクロを定義してtypedef
も、プリプロセッサは気にしないかもしれません。プログラマーは、言語のキーワードと同じ名前で定義されたマクロが存在する場合、正当にシステム ヘッダーを含めることができませんでした。ただし、それ以外の場合typedef
は、プリプロセッサではなく、コンパイラの問題です。それもそうですsizeof()
。これは、プリプロセッサが理解できるものではありません。
通常、前処理された出力を表示できるコンパイラ オプションがあります。の場合gcc
、オプションは-E
と-P
です。
コンパイルに関しては、ソース コードは多くのステップを通過します。そのステップには、前処理があります。
プリプロセッサは、コンパイラの前に実行され、#
開始されたすべての命令 ( 、#include
など)を実行するプログラム#define
です。
あなたの特定のケースで#define WORD newword
は、プログラムをコンパイルしようとする前に、「WORDのすべての出現を新しい単語に置き換える」というディレクティブがあります。
実際の動作を確認したい場合は、実行cpp file.c
して出力を調べて、その動作を理解してください。
file.c
#define WORD "newword"
int main()
{
printf("this is word: %s\n", WORD);
return 0;
}
cppの実行後になります
int main()
{
printf("this is word: %s\n", "newword");
return 0;
}
一方、typedef は、「 について話したらType
、私の意図を理解してください」と言うために使用されます。これはコンパイル時に使用され、パスstruct more_complex_type
の前後で同じままです。cpp
プリプロセッサは、コンパイラがコードをコンパイルする前に実行される「エンジン」です。
#define #include
プリプロセッサ ディレクティブまたはマクロであるため、プリプロセッサ エンジンはディレクティブに関連するコードを実行します。プリプロセッサが完了すると、コンパイラはディレクティブ/マクロを何も認識しません。ただしtypedef
、if
、while
などの構造はコンパイラによって理解されます。
これは、プリプロセッサがコンパイラの前に実行され、コンパイラに渡す前にソース コードを変更することを意味します。したがって、コンパイラはコードの一部を認識しません。例:
#define ONE 1
int x = ONE;
これをコンパイルすると、プリプロセッサはこれを次のように変更します。
int x = 1;
その新しいテキストをコンパイラに渡します。したがって、コンパイラはテキストを認識しませんONE
。