なぜやりたいか
今どきはソースファイルはUTF-8エンコードで保存するのが一般的である。(MicrosoftのVC++はいまだにCP932がデフォルトだが、それについてはこちらの記事を参照)
しかし、組込み系などではいまだ CP932 ベースの日本語文字列処理のライブラリが使われていることもあり、コンパイル時には日本語文字列リテラルはCP932のバイナリに変換したい。
やりかた
GCCのオプションで -fexec-charset=CP932 を指定する。
例
#include <stdio.h> int main(void) { char hoge[] = "あいうえお"; for(int i = 0; i < sizeof(hoge); i++) { printf("%02X ", (unsigned char)hoge[i]); } printf("\n"); }
これをふつうにGCCでビルドして実行すると、下記のような出力結果になる。当然ながら文字列リテラルはUTF-8でエンコードされている。
E3 81 82 E3 81 84 E3 81 86 E3 81 88 E3 81 8A 00
そこで、下記のようなオプション指定でコンパイルする。(ここで hoge.c はソースファイル名、hoge は実行ファイル名だとする。)
gcc -fexec-charset=CP932 hoge.c -o hoge
これを実行すると、下記のような出力結果になる。文字列リテラルがCP932でエンコードされていることが分かる。
82 A0 82 A2 82 A4 82 A6 82 A8 00
ちなみに
-fexec-charset オプションの指定がなければ、文字列リテラルはソースファイルでエンコードされている通りのバイナリにコンパイルされる。よってソースファイルがCP932であればバイナリもCP932になる。-fexec-charset=CP932 を指定すれば、ソースファイルのエンコードが何であれ、CP932に変換されたバイナリになる。
これが上手いやりかたか?
コンパイルオプションでの指定というのは少しうれしくない。現代ではIDEで開発することがふつうだし、IDEが変わればコンパイルオプションの設定方法が違うので、つぶしが効きにくい。
代案として、日本語文字列リテラルを含むソースファイルのみCP932で保存する、という逃げ方がある。しかしこれはこれで文字化けなどのデメリットがある。
- IDEのテキストエディタでCP932のソースを開いたとき文字化けする可能性がある。
- git などのバージョン管理システムでソースを管理する場合、差分表示が文字化けする可能性がある。
- ダメ文字問題で意図しないコンパイル結果になる可能性がある。
ダメ文字問題に関しては、GCCでは -finput-charset=CP932 を指定すれば回避できる。これはソースファイルがCP932であることをコンパイラに明示するオプションである。しかしこの場合は文字列リテラルはUTF-8に変換されてしまうので、-fexec-charset=CP932 を併用する必要があり、今回のケースでは意味が無い。
また、どちらにしても、一つのソースファイル内でUTF-8の文字列リテラルとCP932の文字列リテラルを混在はできない。(そんな必要性があるケースはごく稀だと思うが。)
ダメ文字問題の例
下記のソースではコメント行の末尾にダメ文字「能」があるため、その次の行もコメント扱いになってしまい、printf が実行されなくなる。
#include <stdio.h> int main(void) { char hoge[] = "あいうえお"; for(int i = 0; i < sizeof(hoge); i++) { // ダメ文字→能 printf("%02X ", (unsigned char)hoge[i]); } printf("\n"); }