gcc による utf-8 コンパイルの詳細

gccutf-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 型かに実体が別れるからだ。