gcc による utf-8 コンパイルの詳細
gcc で utf-8 の C ソースコードをコンパイルする場合は、以下のようなコマンドを実行する。
gcc -DUNICODE snow.c
-DUNICODE の詳細
gcc のコマンドラインオプション -DUNICODE
とは、正確には -D
というオプションに UNICODE
という文字列が付加されたものである。
-D<macro>[=<val>] Define a <macro> with <val> as its value. If just <macro> is given, <val> is taken to be 1
gcc のヘルプには、マクロを定義するものであると書かれている。
つまり、-DUNICODE
という指定は、-D
オプションで UNICODE
という名前のマクロを定義するという意味だ。
ソースコード中で指定する
マクロ定義とは、C において #define
で始まるプリプロセッサ命令のことである。
utf-8 で書かれた snow.c 先頭に #define UNICODE
という一行を追加すると、以下のソースコードになる。
#define UNICODE #include <windows.h> int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) { MessageBox(NULL, TEXT("☃"), TEXT(""), MB_OK); return 0; }
gcc snow.c -mwindows
でコンパイルすると、雪だるまマークが正しく表示される。
☃
さらに、これを gcc snow.c -mwindows -DUNICODE
でコンパイルしても、二重にマクロを定義しているという警告が発せられるだけで、正しく表示される。
このことにより、マクロ定義オプション -DUNICODE
と #define UNICODE
というソースコード中のマクロ定義は等しいことがわかる。
ソースコードの先頭に #define UNICODE
を書いておけば、-DUNICODE
によるオプション指定は不要で、書いていなければ、オプションで指定すればよい。
UNICODE マクロによる影響
-DUNICODE
や #define UNICODE
によって、マクロ名 UNICODE を定義すると、Windows API の各関数の挙動が異なってくるので、注意が必要である。
たとえば、MessageBox 関数の場合、UNICODE が定義されていれば、実体は MessageBoxW となり、そうでなければ、MessageBoxA が実体となる。
winuser.h の中で、それぞれ、以下のように宣言されている。
WINUSERAPI int WINAPI MessageBoxA(HWND,LPCSTR,LPCSTR,UINT); WINUSERAPI int WINAPI MessageBoxW(HWND,LPCWSTR,LPCWSTR,UINT);
一部、仮引数の型に違いがある。MessageBoxA では LPCSTR 型となっており、MessageBoxW では LPCWSTR 型となっている。
この場合、MessageBox がどちらに実体化してもいいように、LPCTSTR 型を使用すれば問題ない。LPCTSTR 型もまた、UNICODE 定義によって、LPCWSTR 型か LPCSTR 型かに実体が別れるからだ。