C++ 標準規定 wchar_t 大小與 L"..." 寬字元字面值編碼均為「實作定義」。這導致不同編譯器對中文字元的處理方式截然不同。本文透過實測程式碼,深入分析 VC6.0/VC7.0 (MSVC) 與 GNU g++ (MinGW) 的差異本質。
C++ Primer / Stroustrup:
wchar_t大小由實作定義,需足以容納當地支援的最大字元集。
L'ab'形式的寬字元字面值,其字元數量與含義由實作定義以匹配wchar_t類型。
兩大關鍵點:
wchar_t 長度 = 實作定義L"..." 編碼語義 = 實作定義#include <stdio.h>
#include <windows.h>
void prt(const void* p, size_t n) {
const unsigned char* p = (const unsigned char*)p;
for (size_t i = 0; i < n; ++i) printf(" %02X", p[i]);
printf("\n");
}
int main() {
char a[] = "VC知識庫";
wchar_t b[] = L"VC知識庫";
prt(a, sizeof(a));
prt(b, sizeof(b));
system("pause");
}
| 編譯器 | char[] (MBCS) | wchar_t[] (L"...") |
|---|---|---|
| Dev-C++ 4.9.9.0 (MinGW/g++) | 56 43 D6 AA CA B6 BF E2 00 | 56 00 43 00 D6 00 AA 00 CA 00 B6 00 BF 00 E2 00 00 00 |
| VC6.0 / VC.NET 2003 | 56 43 D6 AA CA B6 BF E2 00 | 56 00 43 00 E5 77 C6 8B 93 5E 00 00 |
L"..." 視為「將非寬字元字面值逐字元擴展」char 高位補 0 擴展為 wchar_t (2 bytes)D6 AA),擴展後變 4 bytes (D6 00 AA 00)L"..." 執行「MBCS → Unicode (UCS-2/UTF-16) 轉換」知=U+77E5, 識=U+8B93, 庫=U+5E93SetWindowTextW 等 Unicode APIMultiByteToWideCharchar a[] = "VC知識庫";
wchar_t b[] = L"VC知識庫";
// 手動轉換 a
int len = MultiByteToWideChar(CP_ACP, 0, a, -1, NULL, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, a, -1, buf, len);
prt(buf, len * sizeof(wchar_t));
// 輸出: 56 00 43 00 E5 77 C6 8B 93 5E 00 00
// 與 VC 版 b[] 完全一致!
HWND h = FindWindow(NULL, "計算機");
SetWindowTextA(h, a); // 兩者皆正常
SetWindowTextW(h, b); // VC 正常顯示「VC知識庫」;MinGW 顯示亂碼
| 層面 | MSVC | GNU g++ (MinGW) |
|---|---|---|
wchar_t 類型 | 內建型別 (2 bytes) | 內建型別 (2 bytes) |
| 原始碼編碼預設 | MBCS (系統代碼頁) | 視環境而定 (常為 UTF-8) |
L"..." 語義 | MBCS → Unicode 轉換 | 逐字元零擴展 |
| 中文字元儲存 | Unicode 碼位 (2 bytes/字) | MBCS 雙位元組各自擴展 (4 bytes/字) |
| Windows Unicode API 相容 | 原生相容 | 需手動轉換 |
#pragma execution_character_set("utf-8") (VS2015+) 或儲存為 UTF-8 with BOM;GCC 預設 UTF-8。u8"..." (C++11) 明確 UTF-8 字面值,配合 char8_t (C++20)。L"..." + W 版 API,並在 MSVC 專案設定「字元集:使用 Unicode 字元集」。std::string),邊界處透過 MultiByteToWideChar/iconv 轉換。L"..." 的實作定義特性,反映 C/C++ 為了可移植性而保留的彈性。在 Windows 平台開發時,理解 MSVC 的 MBCS→Unicode 轉換機制至關重要;跨平台專案則應採用 C++11/20 的 UTF-8 字面值與明確編碼轉換,避免隱性編碼假設導致的難以除錯問題。