1995:C95——寬字元與國際化的補丁#
事件#
1995 年,ISO 發佈 C90 的修正案 ISO/IEC 9899/AMD1:1995(俗稱 C95,又稱 Normative Amendment 1)。這是一個小修訂,主要加入寬字元支援,為即將到來的 C99 鋪路。
為何重要#
- 新語法/函式庫:
wchar_t的正式化(wchar.h、wctype.h)、多位元組字元函式、雙字元萬用轉換(digraph,如<:代表[)、__STDC_VERSION__巨集(值為 199409L)。 - 國際化浪潮:1990 年代軟體全球化(Unicode 1.0 於 1991 年問世),歐洲、亞洲市場要求程式處理非 ASCII 字元。
理論與實用原因(各新特性為何加入)#
wchar_t與寬字元函式庫:- 彌補的缺陷:C90 只有 8 位元的
char,strlen、printf等函式完全無法正確處理中文、日文等非 ASCII 字元,各廠商自創編碼(Shift-JIS、Big5、GB2312)導致程式碼不可攜。 - 理論原因:抽象層次——字元集應與位元組流分離,讓「字元」是邏輯單位而非「一個 byte」。
- 實用原因:
wchar_t讓程式用固定寬度(通常是 16/32 位元)表示字元,wcslen、wprintf對應原本的strlen、printf。 - 雙字元轉換(digraphs)
<:、<%、%>等: - 彌補的缺陷:ISO 646 字元集(某些歐洲鍵盤/編碼)沒有
[、{、#等符號,程式碼根本打不出來。 - 實用原因:讓 lacking 符號的鍵盤環境也能寫 C。
彌補了什麼缺陷#
C95 彌補了 C90「無國際化支援、字元處理綁死 ASCII、某些鍵盤打不出基本符號」的缺陷。但它只是補丁——寬字元與多位元組字元兩套系統並存的混亂,要到 C11 的 char16_t/char32_t 與 Unicode 支援才部分解決。
程式範例#
C90 的缺陷——8 位元 char 處理中文直接失敗:
/* C90:strlen/printf 完全無法正確處理中文 */
char *s = "你好"; /* Big5/GB2312 編碼下是 4 個 byte,UTF-8 下是 6 個 */
printf("%d\n", strlen(s)); /* 4(Big5)?6(UTF-8)?答案依編碼而定! */
printf("%c\n", s[0]); /* 列印「半個字」——亂碼 */
C95 的 wchar_t 與寬字元函式——字元是邏輯單位,不再是一個 byte:
#include <wchar.h>
#include <stdio.h>
#include <locale.h>
int main(void) {
setlocale(LC_ALL, ""); /* 啟用在地化 */
wchar_t *ws = L"你好"; /* L 前綴:寬字元字串 */
wprintf(L"%ls\n", ws); /* 正確列印中文 */
wprintf(L"%d\n", wcslen(ws)); /* 2 —— 兩個「字元」,與編碼無關 */
wchar_t c = L'你';
wprintf(L"%lc\n", c); /* 一個 wchar_t 就是一個字元 */
return 0;
}
$ gcc wc.c -o wc && ./wc
你好
2
你
雙字元轉換(digraphs)——沒有 [、{、# 鍵的歐洲鍵盤也能寫 C:
/* 用 digraphs 寫出等同於 #include、[、{ 的程式碼 */
%:include <stdio.h> /* %: 等同 # */
int main(void)
<% /* <% 等同 { */
int a<:5:> = <%1, 2, 3, 4, 5%>; /* <: :> 等同 [ ], <% %> 等同 { } */
printf("%d\n", a<:2:>);
return 0;
%>