Mingw系のgccで生成される exe ファイルの main() の argv の文字コード

タイトルが長い...
筆者は msys2 を常用し開発作業をしています. 昨日コマンドラインの引数 (main() の argv) にUTF-8の日本語文字列を渡しても正常に動かないケースがあり原因を調べました. そもそも日本語文字列をターミナルで使うということが10年間ぐらいなくてなんでいまさらと、いう話ですけど.

経緯

  • > echo.exe "お尻"
  • > hoge.exe "お尻"
  • main() の argv を調べたらなぜか SJIS になっている
  • shell の locale は関係ない
  • cmd.exe からでも関係ないし、その文字コードも関係ない

調べた

文字コードのことはかいてないのですが、Win32 ネイティブだとパス引数が変換され、互換レイヤだとパス引数が変換されないとあります. また「MSYSのコマンド群はPOSIX互換レイヤで動いています」と書かれているので echo は UTF-8 をいれても UTF-8 がでる理由もつじつまが合います.
http://7shi.hateblo.jp/entry/2012/05/05/220750

このパス引数の変換は /c/windows を c:/windows に変換してくれるというもので、msys2 の shell からは使う身としては大変便利だと思っています. しかしこれが誤動作して困るという記述は世界中にあります.

UTF-8 の文字列を SJIS に勝手に変換するのはコマンド実行から main() 実行の間にパス変換のついでに行われる根拠を見つけることはできませんでした. また変換先が SJIS になるというのも日本語設定の Windows を使っているからのはずで、別の言語だとまた別の文字コードに変換されるのかなど謎が多いです.

対策

そこにあるように msys 互換レイヤとか cygwin を使うなど exe の作成過程をかえることによって直せるものだと思われます. 本当のところはネイティブの exe リンク時に設定を変えられるのが最適なのですけど.

今回の機能は私だけがデバッグに必要なもので、仕方なく iconv を利用して変換された SJIS を main() の最初に UTF-8 に戻すということで回避しました.