跳轉到

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;
%>

相關條目#