C 言語での名前空間の違いの ― 2006年08月24日 11時05分26秒
#define のマクロ、typedef、struct と enum、変数の間で名前空間が違うために、a や A をいっぱい使っても文法的には問題はない。それでも可読性に欠けるので、一部の例外を除いて、利用は控えるべきだ。
#include <stdio.h>
#define a(x) ((x)->a)
typedef int a;
struct a
{
int a;
};
int aa()
{
struct a a = {3};
printf("%d\n", a(&a));
}
int main()
{
a a = 2;
int (*A)() = aa;
printf("%d\n", a);
A();
}
#define の a はプリプロセッサによって処理される。それ故、他の名前空間と別なのは理解しやすい。それぞれ、プリプロセッサとコンパイラの処理は別なのだから、交じりようがないわけだ。
struct と enum の名前空間が存在する。struct a と enum a は共存できない。構造体や列挙型は、必ず struct と enum が付くので、変数を定義するときに、必ず区別が付く。
struct a a;
は構造体 a の型の変数 a を定義している。
それに加えて、typedef だ。私もこれは最初、面白い動作だと思った。struct や enum と同じ名前空間だと思っていたからだ。私は struct や enum も typedef を使って定義するのが好きだ。元々 C++ から始めたから、わざわざ struct や enum を付けるのがあまり好きでないようだ。それに、struct や enum がなくても、構造体なのは判るので。
しかし、ポインタ型や配列型に typedef を使うのは C 言語の中でも一番嫌いな部分だ。これらを定義すると、ポインタ型や配列型だという区別がとても付きにくくなる。わざわざ * や [] を付けて、一目瞭然で判るようにしているのに、それがなくなるので可読性が著しく落ちる。
さて、最後の名前空間は変数だ。関数は変数の中に入る。よく知られているが、aa の中には関数の開始番地が保持されている。aa では、定数の様に変更できないが、関数型として定義された A には、関数を代入することで、実行する関数を変更することが出来る。
実行結果だ。さて、思った通りの結果だっただろうか。 a ではなく c を使った方がもっと混乱してよかっただろうか。
% vi a.c; make a; ./a
cc -O2 -fno-strict-aliasing -pipe a.c -o a
2
3
なお、同じ名前を違う名前空間で使う例外は以下の様な場合だ。typedef を使いたいときに、すっきりできる。
typedef struct node
{
void *data;
struct node *prev;
struct node *next;
} node;
最近のコメント