2008/03/25

gcc と ShiftJIS

文字列リテラルとして「ソー」という表記の含まれている、ShiftJIS でエンコードされたファイルを、gcc でコンパイルする必要が出てきました。元のファイルは(勿論?)Windows上で作られたものです。

そのままコンパイルすると、
foo.c:6:21: warning: unknown escape sequence: '\201'
というエラーになってしまいます。

これは「ソー」をShitfJISでエンコードすると、0x83、0x5c、0x81、0x5bになることが原因です。0x5c(バックスラッシュ)の次の文字として、Cで定義されたエスケープシーケンスを構成する文字(例えば'\'+'n'で「改行」等)を期待しているのに、未知の文字(ここでは、0x81)が来たよ、というエラーです。

ある意味ここまでは想定の範囲内。iconv サポートを有効にして生成された gcc の場合、入力ファイルの文字コードを指定できますから、次のように「このファイルは SJIS ですよ」と指定して、コンパイルしてみました。
% gcc -finput-charset=SJIS -O2 -Wall foo.c
すると今度は、今まで問題なく通っていた'\'がことごとくエラーになってしまいました。慌てて変換結果を良く見ると、なるほど、'\'はすべて0xa5に展開されていました。

実は、これは iconv の採用している ShiftJIS <-> UTF-8 変換テーブルが、Unicode 1.1 で定義された変換テーブルに基づいている為です。JIS X 0201の0x5cは「YEN SIGN」ですから、これは意味論上、全く正しい変換なのですが、今回の例では、少し困ってしまいます。

幸い、Shift-JIS の Windows 版実装とでも言える「Windows-31J」に基づく「CP932」では、UTF-8の変換テーブルでは、'\'は0x5cへと展開するように定義されています。今回は、該当ファイルがWindows上で作られたこともありますので、それを用いることにしましょう。
% gcc -finput-charset=CP932 -O2 -Wall foo.c
今度は問題なくコンパイルできました。

日頃からShiftJISとUnicodeの変換テーブルの揺れが引き起こす問題には気を使っているのですが、まさかコンパイル時に出くわすとは思っていなかったので、新鮮な驚きでした。

というわけで結論。
  • 日本語文字列をコード中に埋め込むのは避けよう。
  • どうしても、ShiftJISでエンコードされた文字列の埋め込まれたコードをコンパイルする場合には、そのファイルがWindows上で生成された場合には、入力ファイルの文字コードにCP932を指定しよう。
なお、FreeBSD 6.3の gcc は iconv での変換が無効化されていますので、注意。

0 件のコメント:

コメントを投稿