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;
コメント
_ jan8 ― 2006年09月11日 15時56分19秒
_ uyota ― 2006年10月24日 11時41分54秒
そこで、試してみました。
goto a;
a:
を足しても、問題なくコンパイルできますね。goto はほとんど使わないのですっかり忘れていました。
_ jan8 ― 2006年11月17日 23時38分41秒
あと、typedefも一つの名前空間なんだそうです。
_ かも ― 2008年04月16日 21時32分44秒
C言語の名前空間について、言語規約(あるいはコンパイラ設計規約)として、出典(書籍名)がありましたら、教えていただけませんか?
私も他の言語からの類推やC言語解説書の記述および手元のコンパイラの動作から、同様の認識ではいるのですが、
他人に説明するときに、今ひとつ説得力に欠けておりまして。
よろしくお願いいたします。
_ uyota ― 2008年05月08日 11時13分41秒
現在の、C 言語は 1999 年 12 月 1 日に発行されたISO/IEC9899:1999 になりますが、そちらに以下の文があります。
6.2.3 Name spaces of identifiers
1. If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates users that refer to different entities, Thus, three are separate name spaces for various categories of identifiers, as follows:
- label names (disambiguated by the syntax of the label declaration and use);
- the tags of structures, unions, and enumerations (disambiguated by following any of the keywords struct, union, or enum);
- the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);
- all other identifiers, called ordinary identifiers ( declared in ordinary declarations or as enumeration constants).
http://www.open-std.org/jtc1/sc22/wg14/ で次版の為のドラフトが進められているようです。その中の http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf が公開されていますが、ここにも上記の文が載っています。
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※なお、送られたコメントはブログの管理者が確認するまで公開されません。
トラックバック
このエントリのトラックバックURL: http://uyota.asablo.jp/blog/2006/08/24/497407/tb
※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。
1.ラベル
2.タグ(struct と enum の名前空間)
3.構造体・共用体のメンバ
4.その他の識別子
に分けられるとなっていますが、
typedefも一つの名前空間ですよね。