PowerShellで、chcp 65001しても文字化けする

powershellgcc

Text

問題

出力のエンコーディングをUTF-8にしたかったがうまくいかなかった:

C言語の日本語を含むファイルをUTF-8で保存し、gccで特にオプションをつけずにコンパイルした。これをWindows ターミナル上のPowerShellやVSCode上のPowerShellで実行すると文字化けした。 検索するとchcp 65001でターミナルをUTF-8にするという情報がヒットしたが、これでもうまくいかなかった。

原因

Claude Codeに調べてもらったところによると、PowerShellモジュールのPSReadLineが悪さをしている可能性がある。こいつは行を読み取るたびに出力側のエンコーディングを932(Shift-JISのCP932)に戻してしまうようだ。実際、chcp 65001; .\hoge.exeのように入力を挟まずに実行すると文字化けしなかった。

調査用のコマンド(Claude作、コメントは実行結果)

Add-Type -Namespace Win32 -Name Con -MemberDefinition @'
[DllImport("kernel32.dll")] public static extern uint GetConsoleCP();
[DllImport("kernel32.dll")] public static extern uint GetConsoleOutputCP();
'@
function Show-CP { "Input: {0} / Output: {1}" -f [Win32.Con]::GetConsoleCP(), [Win32.Con]::GetConsoleOutputCP() }

chcp 65001 > $null; Show-CP # Input: 65001 / Output: 65001
Show-CP                     # Input: 65001 / Output: 932

Remove-Module PSReadLine

chcp 65001 > $null
Show-CP                     # Input: 65001 / Output: 65001

どうするか

chcpと同時に実行する

先述の通りchcp 65001; .\hoge.exeのように入力を挟まなければ文字化けしない。

別のコマンドを使う

[Console]::OutputEncoding = [Text.Encoding]::UTF8なら同じセッション中は戻らない

gccに-fexec-charset=cp932オプションを付ける

UTF-8からShift-JISにコンパイルする。最初からShift-JISにすれば問題なし

PowerShellを使わない

cmdならPSReadLineがいないので、普通にchcpすればおk。またはwsl上でビルド・実行をすれば、wslの出力エンコーディングがUTF-8なので問題は起きない。