#define
による定数の定義というのはあくまでもプリプロセッサが行う「字句的な置き換え」であって、処理のレイヤが違うのです。 マクロは通常のスコープの一般原則を超越してあらゆる箇所に現れるトークンを置き換えます。
通常の変数や (enum
による定義を含む) 定数は同名のものがあった場合にはよりスコープが狭いほうが優先されるという原則がありますが、マクロはそうではありません。
単純な例でいえば
c
1#include <stdio.h>
2
3enum JAPAN{
4 TOKYO,
5 OSAKA,
6 KYOTO,
7};
8
9int main(void) {
10 const int TOKYO = 10;
11 printf("%d\n", TOKYO);
12}
といったように enum
内で定義した TOKYO
よりも main
内で定義した TOKYO
のほうが優先されます。
これを enum
ではなく #define
による定義にするとどうなるでしょうか。
c
1#include <stdio.h>
2
3#define TOKYO 0
4#define OSAKA 1
5#define KYOTO 2
6
7int main(void) {
8 const int TOKYO = 10;
9 printf("%d\n", TOKYO);
10}
プリプロセッサによる置き換えによって
c
1#include <stdio.h>
2
3int main(void) {
4 const int 0 = 10;
5 printf("%d\n", TOKYO);
6}
と同様の状態になってエラーになってしまいます。
#define
による定義では全部を大文字の名前にする (それ以外はそうしない) という習慣があるのはマクロ名がマクロでない名前と衝突するとろくでもないことが起こるのがわかっているからです。
もうひとつの理由は「意図の表現」です。 プログラムはコンパイラが解釈して実行プログラムを生成するというだけでなくあなた以外のプログラマが読むこともあるという事実も忘れてはいけません。
たとえば
c
1#include <stdio.h>
2
3enum JAPAN {
4 TOKYO,
5 OSAKA,
6 KYOTO,
7};
8
9void foo(enum JAPAN x) {
10 printf("%d", x);
11}
と書いてあれば「foo
という関数は (引数として) 日本のどこかであるかを受け取るのだな」という意図が読み取れます。
これが
c
1#include <stdio.h>
2
3#define TOKYO 0
4#define OSAKA 1
5#define KYOTO 2
6
7void foo(int x) {
8 printf("%d", x);
9}
だと foo
が受けとる変数が何者であるのかというのは (実質の処理内容が同じだとしても) 字面から読み取るのが難しくなります。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。