おまじないではない#include
C言語を最初に学ぶと、必ず出てくる以下の行
#include <stdio.h>
おなじないと言われて、常に書いている人がいるみたいだが、おまじないでもなんでもなくて stdio.h ファイルをそこに展開せよといっているだけである。
なんで展開するかというと、たいていはprintf関数を使うので、そのプロトタイプ宣言なんかが書いてあって必要になるから。使う分にはそれでもいいけど、それだと面白くないからstdio.hファイルでも見てみようかと思うわけですよ。
どこにあるかというと、まぁ、環境によるわけですが、UNIX系の場合 /usr/include だったりします。 というわけで、/usr/include/stdio.hファイルを見ていけばいいということで。以下、FreeBSD 7.3-RELEASE の環境の話です。
ファイル長いので、面白そうなとこだけ見ていこうかと。
最初は以下の通り。なお、先頭の番号は行番号。
40 #ifndef _STDIO_H_ 41 #define _STDIO_H_ 42 43 #include <sys/cdefs.h> 44 #include <sys/_null.h> 45 #include <sys/_types.h>
いきなり、意味分からん書き方。_STDIO_H_ が定義されていなかったら定義する、ってどういうこっちゃ。これ、このファイルを読み込んだら _STDIO_H_ を定義する、ただし、別の箇所で再度#include
で、この定義名の命名規則を決めておくと、どのファイルを読み込んだかも分かるっていうトリッキーなやりかた。この場合、ファイル名の両端に_を付けて.を_にし、大文字にするという規則。
さて、次の行から三連ちゃんで別のファイルをincludeしている。実体は /usr/include/sys/cdefs.h、/usr/include/sys/_null.h、/usr/include/sys/_types.h にある。
cdefs.hは、まぁ、内部的に使ういろんなのが#define されてます。
_null.h は、そのままで NULL の定義が書いてます。短いのでみてみると、
29 #ifndef NULL 30 31 #if !defined(__cplusplus) 32 #define NULL ((void *)0) 33 #else 34 #if defined(__GNUG__) && defined(__GNUC__) && __GNUC__ >= 4 35 #define NULL __null 36 #else 37 #if defined(__LP64__) 38 #define NULL (0L) 39 #else 40 #define NULL 0 41 #endif /* __LP64__ */ 42 #endif /* __GNUG__ */ 43 #endif /* !__cplusplus */ 44 45 #endif
31行目でC++かどうかの判定ですね。そうでなければ(C言語の場合)、NULLは (void*)0 なわけです。そうですね、C言語ではNULLはポインタなんですよね。だからポインタへのキャストしているわけですね。C言語でvoid *はなんでもOKなポインタだから出来る技になっております。C++の場合、少しやっかいになって、void *の扱いが変わるためいろいろ面倒なことになっているんですね。だから、0を特別なポインタとして扱うようにして、まぁ、なんとかやってるわけです。
つづきはまた今度