Logo

dev-resources.site

for different kinds of informations.

Windows 上 VSCode 的 C/C++ 延伸模組處理編碼的問題

Published at
1/15/2025
Categories
cpp
vscode
powershell
cmd
Author
codemee
Categories
4 categories in total
cpp
open
vscode
open
powershell
open
cmd
open
Author
7 person written this
codemee
open
Windows 上 VSCode 的 C/C++ 延伸模組處理編碼的問題

VSCode 雖然可以使用 C/C++ 延伸模組開發 C/C++ 程式,不過因為 Windows 平台的特殊性,所以實務上你可能會遇到中文文字編碼的問題。

預設的輸出輸入編碼

我們以底下這個顯示終端機文字輸入輸出編碼的程式為例來觀察編碼的變化:

#include <iostream>
#include <Windows.h>

using namespace std;

int main()
{
    cout << "Console input encoding: " << GetConsoleCP() << endl;
    cout << "Console output encoding: " << GetConsoleOutputCP() << endl;
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

在 VSCode 中,我們先開啟終端機來觀察預設的編碼,首先是 PowerSehll 5:

PS C:\Users\meebo\code\cpp> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      26100  2161


PS C:\Users\meebo\code\cpp> .\encoding.exe
Console input encoding: 950
Console output encoding: 950
Enter fullscreen mode Exit fullscreen mode

接著是 PowerShell 7:

# $PSVersionTable.PSVersion

Major  Minor  Patch  PreReleaseLabel BuildLabel
-----  -----  -----  --------------- ----------
7      4      6

# .\encoding.exe
Console input encoding: 950
Console output encoding: 950
Enter fullscreen mode Exit fullscreen mode

以及 cmd:

C:\Users\meebo\code\cpp>ver

Microsoft Windows [版本 10.0.26100.2605]

C:\Users\meebo\code\cpp>.\encoding.exe 
Console input encoding: 950
Console output encoding: 950
Enter fullscreen mode Exit fullscreen mode

你可以看到繁體中文版 Windows 上各種 shell 預設輸入輸出的文字編碼都是字碼頁 950 的 Big5 繁體中文。

C/C++ 延伸模組會強制採用 utf-8 編碼

不過 C/C++ 延伸模組執行程式時是透過 WindowsDebugLauncher,它會把終端機的輸出輸入編碼都改為 utf-8,不管你的 VSCode 預設採用哪一種 shell,執行結果都會是這樣:

#  & 'c:\Users\meebo\scoop\apps\vscode\1.96.3\data\extensions\ms-vscode.cpptools-1.22.11-win32-x64\debugAdapters\bin\WindowsDebugLauncher.exe' '--stdin=Microsoft-MIEngine-In-ftut4mzx.zwc' '--stdout=Microsoft-MIEngine-Out-su2vyt31.p3w' '--stderr=Microsoft-MIEngine-Error-3dspx1tz.n14' '--pid=Microsoft-MIEngine-Pid-cywhpozy.otf' '--dbgExe=C:\Users\meebo\scoop\shims\gdb.exe' '--interpreter=mi' 
Console input encoding: 65001
Console output encoding: 65001
Enter fullscreen mode Exit fullscreen mode

你可以看到終端機的輸出輸入都變成採用字碼頁 65001 的 utf-8 編碼,也就是說,如果你以為終端機預設使用 Big5 編碼,所以就採用 Big5 編碼的文字送出,就會被當成 utf-8 編碼解譯錯誤變亂碼。舉例來說,以下這個送出 "測試" 兩個字 Big5 編碼的程式檔:

#include <iostream>

using namespace std;

int main()
{
    // "測試" 的 Big5 編碼為 0xB4FA 0xB8D5
    cout << "\xB4\xFA\xB8\xD5" << endl;
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

透過 C/C++ 延伸模組的執行結果如下:

#  & 'c:\Users\meebo\scoop\apps\vscode\1.96.3\data\extensions\ms-vscode.cpptools-1.22.11-win32-x64\debugAdapters\bin\WindowsDebugLauncher.exe' '--stdin=Microsoft-MIEngine-In-mryt1wru.tik' '--stdout=Microsoft-MIEngine-Out-y3eekozn.ws1' '--stderr=Microsoft-MIEngine-Error-ohiqqkkb.vhb' '--pid=Microsoft-MIEngine-Pid-iks4j4h0.j5l' '--dbgExe=C:\Users\meebo\scoop\shims\gdb.exe' '--interpreter=mi' 
����
Enter fullscreen mode Exit fullscreen mode

你可以看到輸出變成亂碼了,但如果你接著在同一個終端機中直接執行編譯好的檔案:

# .\print_big5.exe
測試
Enter fullscreen mode Exit fullscreen mode

其實是正常的,這就是因為 C/C++ 延伸模組把 Big5 編碼的文字當成 uft-8 解讀的關係。如果換成以下這個輸出 "測試" 兩字 utf-8 編碼的程式:

#include <iostream>

using namespace std;

int main()
{
    // "測試" 的 utf-8 編碼為 0xE6 0xB8 0xAC 0xR8 0xA9 0xA6
    cout << "\xE6\xB8\xAC\xE8\xA9\xA6" << endl;
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

就會變成在 C/C++ 延伸模組執行正常顯示,但是接著在終端機中直接執行會變亂碼了:

#  & 'c:\Users\meebo\scoop\apps\vscode\1.96.3\data\extensions\ms-vscode.cpptools-1.22.11-win32-x64\debugAdapters\bin\WindowsDebugLauncher.exe' '--stdin=Microsoft-MIEngine-In-v21amcfg.pjg' '--stdout=Microsoft-MIEngine-Out-k5iwq2gi.oev' '--stderr=Microsoft-MIEngine-Error-g4udotjf.znd' '--pid=Microsoft-MIEngine-Pid-cpnn5efq.cbc' '--dbgExe=C:\Users\meebo\scoop\shims\gdb.exe' '--interpreter=mi' 
測試
# .\print_utf8.exe
皜祈岫
Enter fullscreen mode Exit fullscreen mode

這就是因為 C/C++ 延伸模組採用 utf-8 編碼,但執行之後終端機的輸出編碼復原為 Big5 編碼的關係。

C/C++ 延伸模組不會復原輸入編碼

更麻煩的是,從剛剛的結果看起來,似乎 C/C++ 模組執行完後會復原終端機原本的編碼,不過實際上它只復原了輸出文字的編碼,輸入文字的編碼仍然是 utf-8,這可以透過再次執行剛剛看過的 encoding 程式或者下達指令來確認:

# .\encoding.exe
Console input encoding: 65001
Console output encoding: 950
# [Console]::InputEncoding.EncodingName   
Unicode (UTF-8)
# [Console]::OutputEncoding.EncodingName
Chinese Traditional (Big5)
Enter fullscreen mode Exit fullscreen mode

我們可以透過以下這個簡單的程式來確認輸入文字採用的編碼:

#include <stdio.h>
#include <unistd.h>

int main( ) {
  unsigned char c;
  int count;

  while((count=read(0, &c, 1))>0) {
    printf("\\x%02X", c);
    if(c==0x0a) {
      return 0;
    }
  }
  return 0;
}
Enter fullscreen mode Exit fullscreen mode

它會把輸入的文字一個一個位元組印出來,透過 C/C++ 延伸模組執行如下:

#  & 'c:\Users\meebo\scoop\apps\vscode\1.96.3\data\extensions\ms-vscode.cpptools-1.22.11-win32-x64\debugAdapters\bin\WindowsDebugLauncher.exe' '--stdin=Microsoft-MIEngine-In-uazxwyvw.wjc' '--stdout=Microsoft-MIEngine-Out-w0qz4rdi.rgw' '--stderr=Microsoft-MIEngine-Error-ptpraqag.z2k' '--pid=Microsoft-MIEngine-Pid-fauxn3rk.ra5' '--dbgExe=C:\Users\meebo\scoop\shims\gdb.exe' '--interpreter=mi' 
測試
\xE6\xB8\xAC\xE8\xA9\xA6\x0A
Enter fullscreen mode Exit fullscreen mode

你可以看到它輸出的是 "測試" 的 utf-8 編碼,即使在 C/C++ 延伸模組執行後接著直接執行:

# .\getch.exe   
測試
\xE6\xB8\xAC\xE8\xA9\xA6\x0A
Enter fullscreen mode Exit fullscreen mode

結果也是一樣。但是如果你在本文一開始檢視終端機輸出輸入編碼時的 PowerShell 5 中測試:

PS C:\Users\meebo\code\cpp> .\encoding.exe
Console input encoding: 950
Console output encoding: 950
PS C:\Users\meebo\code\cpp> .\getch.exe
測試
\xB4\xFA\xB8\xD5\x0A
Enter fullscreen mode Exit fullscreen mode

就會看到輸出結果是 "測試" 的 Big5 編碼。所以如果你有一個像是以下這樣簡單的程式:

#include <iostream>

using namespace std;

char s[20];

int main()
{
    cin >> s;
    cout << s << endl;
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

執行結果就會是這樣:

#  & 'c:\Users\meebo\scoop\apps\vscode\1.96.3\data\extensions\ms-vscode.cpptools-1.22.11-win32-x64\debugAdapters\bin\WindowsDebugLauncher.exe' '--stdin=Microsoft-MIEngine-In-e11e0kys.134' '--stdout=Microsoft-MIEngine-Out-zjw1kn0z.0mh' '--stderr=Microsoft-MIEngine-Error-2nzxpcy2.uhm' '--pid=Microsoft-MIEngine-Pid-0phnnj0p.icr' '--dbgExe=C:\Users\meebo\scoop\shims\gdb.exe' '--interpreter=mi' 
測試
測試
# .\simple_echo.exe
測試
皜祈岫
Enter fullscreen mode Exit fullscreen mode

在 C/C++ 延伸模組執行因為輸入與輸出的編碼是一致的,所以可以正常顯示;但是接著單獨執行時,就會因為現在輸入是 utf-8 但輸出是 Big5 而錯亂。如果我們強制設定輸出採用和輸入一樣的編碼:

# [Console]::OutputEncoding = [Console]::InputEncoding
# .\simple_echo.exe
測試
測試
Enter fullscreen mode Exit fullscreen mode

就可以正常顯示了。

結語

我不知道為什麼 C/C++ 延伸套件要這樣設計,理論上應該是要套用終端機本身採用的輸入輸出編碼才對,否則只是要寫寫簡易的程式,可能就會被搞得大亂,尤其是初學者應該更是昏頭。在 github 上也有人提到了相同的問題

在其他平台上,因為終端機預設的輸入輸出編碼都是 utf-8,不會像是 Windows 這樣終端機本身的編碼和 C/C++ 延伸模組採用的編碼不一致,就不會有這樣的問題。

cmd Article's
30 articles in total
Favicon
Windows 上 VSCode 的 C/C++ 延伸模組處理編碼的問題
Favicon
TryHackMe | Windows Command Line | RSCyberTech
Favicon
50+ Most Useful CMD Commands to Boost Your Windows Productivity
Favicon
Video: Enable IIS using CMD and PowerShell
Favicon
Video: List All Available Windows Features on Windows 11 using CMD & PowerShell
Favicon
🚀 Arch Linux Cheat Sheet: Essential Commands for new Users
Favicon
RIME Input | curl: (6) Could not resolve host: raw.githubusercontent.com
Favicon
Rename Multiple Files in Sequence with Just One Click Using PowerShell in Windows! 🚀
Favicon
Maximizing IT Service Excellence with ServiceNow CMDB
Favicon
🍑understanding windows Command Line Interface
Favicon
Comandos Avanzados
Favicon
Comandos de Red
Favicon
Comandos de Fecha
Favicon
Comandos para Manipular Archivos y Directorios
Favicon
Tech notes 02 - Most Important Command Line Notes
Favicon
Comandos Básicos
Favicon
Bash Scripting Fundamentals
Favicon
Decoding the Linux Command Line: 75 Indispensable Utilities Explained
Favicon
How to restore a Mysql backup with XAMP
Favicon
Remotely Control Raspberry Pi via SSH from External Network
Favicon
SSH Raspberry Pi via Cell Phone
Favicon
Enhancing Internet Speed Through CMD Commands
Favicon
Install Oh-My-Posh On Windows Command Prompt (cmd) Via Clink
Favicon
Important CMD Commands
Favicon
Title: A Beginner's Guide to Command-Line File and Directory Manipulation
Favicon
Mastering Deployments in Kubernetes
Favicon
SetEnv 工具程式
Favicon
My K8s Cheatsheet
Favicon
Membuat Database Melalui CMD Pada Laragon
Favicon
Perbedaan perintah RUN dan CMD di dalam Docker

Featured ones: