##プリプロセッサ指令 「文字の集合であるソースコード上で機能する命令」
コンピュータの前処理プログラム、予備処理、つまりコンピュータ処理で中心的なプログラムの条件に合わせる為の事前処理を行う)
コンパイラでは、人間の記述したソースコードを機械語に翻訳するが、その前に段階としてソースコードに一定の規則に従って処理を加えるのが、プリプロセッサの役割となる。
要約
#ifndef, #define, #endifと書いてある行は、C言語で二重にヘッダーファイルが読み込まれるのを防ぐのによく使われる方法
このやり方をしないと何度もヘッダーファイルが読み込まれることになって、変数や定数が何度も定義されてしまい、コンパイルエラーになるのです。
#ifdef
機能: 識別子が定義されているかどうかの判定を行う。
(識別子名)が定義済みなら処理を行う。処理とは、プリプロセッサに対する指令。
識別子は#defineで値を定義するが、未定義の場合は「0」、つまり何も返さない。
書式: #ifdef (識別子名)
処理
#define
機能: 文字列の置き換え。
識別子(文字列1)を値(文字列2)と定義します。この時、#defineでは文字列同士の置き換えを行っています。なぜならプリプロセッサ指令はあくまでソースファイルに記述された文字列 =>ソースコードを扱っているの過ぎないからです。
#define __MAX 100
とすれば、コンパイルの段階では、"__MAX"という記号が整数型(Int)の100に置き換えられています。ソースコード上では文字列の"__MAX"が"100"という文字列の置き換えられています。
プリプロセッサ指令はあくまで「文字の集合であるソースコード上で機能する命令」と定義できます。
#endif
機能: #ifdefや#ifndefなどにより処理ブロックの最後に明示する。
#ifdefや#ifndef共に結果が「真」なら(処理)を一行実行します。
##参考例
下記のような、条件によってコンパイルしたり、しなかったりを制御することを「条件コンパイル」と言います。
要約 識別子内部の処理を毎回行わせることで、毎回定義されることを防ぐ。
あるプログラムで、Sample.hが初めてインクルードされた時を考えます。
1 はじめはINCLUDED_Sample_h_は定義されていません。したがって#ifdefは無視され、 const float PI = 3.14159;がコンパイルされます。
そして、#defineによってINCLUDED_Sample_h_が定義されます。
2 二回目以降にSample.hがインクルードされると、すでにINCLUDED_Sample_h_が定義されています。このため、#ifdefにより、#defineとconst float PI = 3.14159が無視され、コンパイルされません。
つまり、一つのプログラムでSample.hが何回インクルードされても定義は一回です。
そして、#ifdef識別子内部の処理を、読み込まれるたびに行います。
Sample.hファイル
#ifndef INCLUDED_Sample_h_
#define INCLUDED_Sample_h_
const float PI = 3.14159;
#endif
参考URL
https://www.grapecity.com/tools/support/powernews/column/clang/014/page02.html