logo

C プリプロセッサ

プリプロセッサは、コンパイル前にソース コードを処理するプログラムです。 C でプログラムを作成してから実行するまでには、いくつかの手順が必要です。実際にプリプロセッサについて学び始める前に、これらの手順を見てみましょう。

Cのプリプロセッサ



上の図で中間のステップを確認できます。プログラマーが書いたソースコードは、まずファイルに保存されます。その名前は次のとおりです。 プログラム.c 。このファイルはプリプロセッサによって処理され、program.i という名前の拡張されたソース コード ファイルが生成されます。この展開されたファイルはコンパイラによってコンパイルされ、program.obj という名前のオブジェクト コード ファイルが生成されます。最後に、リンカはこのオブジェクト コード ファイルをライブラリ関数のオブジェクト コードにリンクして、実行可能ファイル Program.exe を生成します。

C のプリプロセッサ ディレクティブ

プリプロセッサ プログラムは、コンパイル前にソース コードを前処理するようにコンパイラに指示するプリプロセッサ ディレクティブを提供します。これらのプリプロセッサ ディレクティブはすべて「#」 (ハッシュ) 記号で始まります。 「#」記号は、「#」で始まるステートメントがプリプロセッサ プログラムに送られて実行されることを示します。これらのプリプロセッサ ディレクティブはプログラム内のどこにでも配置できます。

いくつかのプリプロセッサ ディレクティブの例は次のとおりです。 #含む #定義する #ifndef、



注記 覚えておいてください。 # シンボルはプリプロセッサへのパスを提供するだけであり、include などのコマンドはプリプロセッサ プログラムによって処理されます。たとえば、#include は、指定されたファイルのコードまたはコンテンツをプログラムに組み込みます。

C のプリプロセッサ ディレクティブのリスト

次の表に、C のすべてのプリプロセッサ ディレクティブを示します。

プリプロセッサディレクティブ

説明



#定義する

マクロを定義するために使用されます

#undef

json形式の例
マクロの定義を解除するために使用されます

#含む

ソースコードプログラムにファイルを含めるために使用されます

#ifdef

特定のマクロが #define で定義されている場合に、コードのセクションを含めるために使用されます。

#ifndef

特定のマクロが #define で定義されていない場合に、コードのセクションを含めるために使用されます。

#もし

指定された条件を確認する

#それ以外

#if が失敗したときに実行される代替コード

#endif

#if、#ifdef、#ifndef の終わりをマークするために使用されます

これらのプリプロセッサは、実行する機能のタイプに基づいて分類できます。

C プリプロセッサの種類

プリプロセッサ ディレクティブには主に 4 つのタイプがあります。

  1. マクロ
  2. ファイルのインクルード
  3. 条件付きコンパイル
  4. その他の指令

これらの各ディレクティブについて詳しく見てみましょう。

1.マクロ

C では、マクロは、何らかの名前が付けられたプログラム内のコードの一部です。コンパイラーがこの名前を検出すると、コンパイラーはその名前を実際のコード部分に置き換えます。の '#定義する' ディレクティブはマクロを定義するために使用されます。

マクロ定義の構文

  #define     token     value>

ここで、前処理の後、 トークン まで拡張されます 価値 プログラム内で。

マクロの例

C




// C Program to illustrate the macro> #include> // macro definition> #define LIMIT 5> int> main()> {> >for> (>int> i = 0; i printf('%d ', i); } return 0; }>

>

>

出力

0 1 2 3 4>

上記のプログラムでは、コンパイラが LIMIT という単語を実行すると、それを 5 に置き換えます。 「リミット」 マクロ定義で マクロテンプレートと呼ばれます そして 「5」はマクロ展開です。

注記 マクロ定義の末尾にセミコロン (;) はありません。マクロ定義の終わりにセミコロンは必要ありません。

いくつかもあります C の定義済みマクロ これらは、プログラムにさまざまな機能を提供するのに役立ちます。

引数付きマクロ

マクロに引数を渡すこともできます。引数を使用して定義されたマクロは、関数と同様に機能します。

  #define   foo(  a, b  )   a + b  #define func(r) r * r>

これをプログラムで理解してみましょう。

C


コレクション Java



// C Program to illustrate function like macros> #include> // macro with parameter> #define AREA(l, b) (l * b)> int> main()> {> >int> l1 = 10, l2 = 5, area;> >area = AREA(l1, l2);> >printf>(>'Area of rectangle is: %d'>, area);> >return> 0;> }>

>

>

出力

Area of rectangle is: 50>

上記のプログラムから、コンパイラーがプログラム内で AREA(l, b) を見つけるたびに、それをステートメント (l*b) に置き換えることがわかります。これだけでなく、マクロ テンプレート AREA(l, b) に渡された値もステートメント (l*b) で置き換えられます。したがって、AREA(10, 5) は 10*5 と等しくなります。

2. ファイルのインクルード

このタイプのプリプロセッサ ディレクティブは、ソース コード プログラムにファイルを含めるようコンパイラに指示します。の #include プリプロセッサ ディレクティブ C プログラムにヘッダー ファイルをインクルードするために使用されます。

ユーザーがプログラムに含めることができるファイルには次の 2 種類があります。

PythonはJSONをファイルに保存します

標準ヘッダー ファイル

標準ヘッダー ファイルには、次のような事前定義関数の定義が含まれています。 printf()、scanf()、 これらの関数を使用するには、これらのファイルを含める必要があります。異なる関数は異なるヘッダー ファイルで宣言されます。
たとえば、標準 I/O 関数は「iostream」ファイルにありますが、文字列操作を実行する関数は「string」ファイルにあります。

構文

  #include   <  file_name>>>

どこ ファイル名 インクルードされるヘッダー ファイルの名前です。の 「」括弧 コンパイラに s 内のファイルを探すように指示します。 標準ディレクトリ。

ユーザー定義のヘッダー ファイル

プログラムが非常に大きくなる場合は、プログラムを小さなファイルに分割し、必要に応じてそれらをインクルードすることをお勧めします。これらのタイプのファイルはユーザー定義のヘッダー ファイルです。

構文

  #include   '  filename  '>

二重引用符 ( ) ヘッダー ファイルを検索するようにコンパイラーに指示します。 ソースファイルのディレクトリ。

3. 条件付きコンパイル

C ディレクティブの条件付きコンパイル は、プログラムの特定の部分をコンパイルしたり、条件に基づいてプログラムの特定の部分のコンパイルをスキップしたりするのに役立つディレクティブの一種です。条件付きコードを挿入するために使用される次のプリプロセッサ ディレクティブがあります。

  1. #if ディレクティブ
  2. #ifdef ディレクティブ
  3. #ifndef ディレクティブ
  4. #else ディレクティブ
  5. #elif ディレクティブ
  6. #endif ディレクティブ

#endif ディレクティブは、#if、#ifdef、#ifndef の開始ディレクティブを閉じるために使用されます。これは、これらのディレクティブの前処理が完了したことを意味します。

構文

  #ifdef     macro_name   // Code to be executed if macro_name is defined #  ifndef     macro_name   // Code to be executed if macro_name is not defined   #if    constant_expr   // Code to be executed if constant_expression is true   #elif     another_constant_expr   // Code to be excuted if another_constant_expression is true   #else   // Code to be excuted if none of the above conditions are true   #endif>

「」という名前のマクロの場合、 マクロ名 ' が定義されている場合、ステートメントのブロックは通常どおり実行されますが、定義されていない場合、コンパイラーはこのステートメントのブロックを単純にスキップします。

以下の例は、#include #if、#elif、#else、および #endif プリプロセッサ ディレクティブの使用を示しています。

C




//program to demonstrates the use of #if, #elif, #else,> // and #endif preprocessor directives.> #include> // defining PI> #define PI 3.14159> int> main()> {> > #ifdef PI> >printf>(>'PI is defined '>);> > #elif defined(SQUARE)> >printf>(>'Square is defined '>);> #else> >#error 'Neither PI nor SQUARE is defined'> #endif> > #ifndef SQUARE> >printf>(>'Square is not defined'>);> #else> >cout <<>'Square is defined'> << endl;> #endif> >return> 0;> }>

>

>

出力

PI is defined Square is not defined>

4. その他の指令

上記のディレクティブとは別に、一般的に使用されないディレクティブがさらに 2 つあります。これらは:

  1. #undef ディレクティブ
  2. #pragma ディレクティブ

1. #undef ディレクティブ

#undef ディレクティブは、既存のマクロの定義を解除するために使用されます。このディレクティブは次のように機能します。

#undef LIMIT>

このステートメントを使用すると、既存のマクロ LIMIT の定義が解除されます。このステートメントの後、すべての #ifdef LIMIT ステートメントは false として評価されます。

以下の例は、#undef ディレクティブの動作を示しています。

C




int から文字列への変換

#include> // defining MIN_VALUE> #define MIN_VALUE 10> int> main() {> >// Undefining and redefining MIN_VALUE> printf>(>'Min value is: %d '>,MIN_VALUE);> > //undefining max value> #undef MIN_VALUE> > // again redefining MIN_VALUE> #define MIN_VALUE 20> >printf>(>'Min value after undef and again redefining it: %d '>, MIN_VALUE);> >return> 0;> }>

>

>

出力

Min value is: 10 Min value after undef and again redefining it: 20>

2. #pragma ディレクティブ

このディレクティブは特別な目的のディレクティブであり、一部の機能をオンまたはオフにするために使用されます。これらのタイプのディレクティブはコンパイラ固有です。つまり、コンパイラごとに異なります。

構文

#pragma   directive>

#pragma ディレクティブの一部については、以下で説明します。

  1. #プラグマの起動: これらのディレクティブは、プログラムの起動前 (制御が main() に渡される前) に実行する必要がある関数を指定するのに役立ちます。
  2. #プラグマ終了 : これらのディレクティブは、プログラムが終了する直前 (コントロールが main() から戻る直前) に実行する必要がある関数を指定するのに役立ちます。

以下のプログラムは GCC コンパイラでは動作しません。

以下のプログラム #pragma exit と pragma starting の使用法を示します。

C




// C program to illustrate the #pragma exit and pragma> // startup> #include> void> func1();> void> func2();> // specifying funct1 to execute at start> #pragma startup func1> // specifying funct2 to execute before end> #pragma exit func2> void> func1() {>printf>(>'Inside func1() '>); }> void> func2() {>printf>(>'Inside func2() '>); }> // driver code> int> main()> {> >void> func1();> >void> func2();> >printf>(>'Inside main() '>);> >return> 0;> }>

>

>

期待される出力

Inside func1() Inside main() Inside func2()>

上記のコードを GCC コンパイラで実行すると、次のような出力が生成されます。

Inside main()c>

これは、GCC が #pragma の起動または終了をサポートしていないために発生します。ただし、以下のコードを使用すると、GCC コンパイラで期待される出力を得ることができます。

C




#include> void> func1();> void> func2();> void> __attribute__((constructor)) func1();> void> __attribute__((destructor)) func2();> void> func1()> {> >printf>(>'Inside func1() '>);> }> void> func2()> {> >printf>(>'Inside func2() '>);> }> int> main()> {> >printf>(>'Inside main() '>);> >return> 0;> }>

JavaScript

>

>

出力

Inside func1() Inside main() Inside func2()>

上記のプログラムでは、いくつかを使用しました 特定の構文 つまり、関数の 1 つは main 関数の前に実行され、もう 1 つは main 関数の後に実行されます。

#pragma warn ディレクティブ

このディレクティブは、コンパイル中に表示される警告メッセージを非表示にするために使用されます。以下に示すように、警告を非表示にすることができます。

  • #pragma warn -rvl : このディレクティブは、値を返すはずの関数が値を返さない場合に発生する警告を非表示にします。
  • #pragma warn -par : このディレクティブは、関数に渡されたパラメーターが使用されない場合に発生する警告を非表示にします。
  • #プラグマ警告 -rch : このディレクティブは、コードに到達できないときに発生する警告を非表示にします。たとえば、 戻る 関数内のステートメントに到達できません。

techcodeview.com が気に入って貢献したい場合は、次を使用して記事を書くこともできます。 。 techcodeview.com メイン ページにあなたの記事が掲載されているのを見て、他のオタクを助けてください。間違った点を見つけた場合、または上記のトピックについてさらに詳しい情報を共有したい場合は、コメントを書いてください。