Windows 程式設計/Unicode
有關 Unicode 標準的參考,請參見 Unicode。
Unicode 是一個行業標準,其目標是提供一種方法,使各種形式和語言的文字能夠被計算機編碼使用。最初,文字字元在計算機中使用位元組寬資料表示:每個可列印字元(以及許多不可列印字元或“控制”字元)都使用單個位元組實現,這允許總共 256 個字元。然而,全球化帶來了對計算機能夠適應世界各地許多不同字母的需求。
舊程式碼稱為 ASCII 或 EBCDIC,但很明顯,這些程式碼都無法處理來自世界各地的所有不同字元和字母。Unicode 是解決這個問題的方案。Windows NT 使用“寬”16 位字元集實現其許多核心功能,接近 Unicode 標準,儘管它也提供了一系列與標準 ASCII 字元相容的功能。
UNICODE 字元通常稱為“寬字元”、“通用字元”或“T 字元”。本書可能會互換使用這些術語。
在 Unicode 之前,有一種國際化嘗試引入了具有變長字元的字串。一些字元,例如標準 ASCII 字元,將是 1 位元組長。其他字元,例如擴充套件字元集,是 2 位元組長。隨著 UNICODE 的出現,這類字元格式不再受歡迎,因為它們更難編寫,也更難閱讀。Windows 仍然維護一些功能來處理變長字串,但我們不會在這裡討論這些功能。
不幸的是,由於所需的字元數量很快超過了 65,536 個可能的 16 位值,使用寬字元的所有優勢都消失了。Windows 實際上使用稱為 UTF-16 的方法來儲存字元,其中大量字元實際上佔用 //兩個// 字,這些稱為“代理對”。這種發展是在大部分 Windows API 文件編寫之後發生的,現在很多都已過時。您永遠不應該將字串資料視為“字元陣列”,而應該始終將其視為以 null 結尾的塊。例如,始終將整個字串傳送到函式以在螢幕上繪製它,不要嘗試繪製每個字元。任何在 LPSTR 後面加上方括號的程式碼都是錯誤的。
同時,變長字元字串在稱為 UTF-8 的跨平臺標準中強勢迴歸,UTF-8 與 UTF-16 相同,但使用 8 位單元。它的主要優勢在於無需兩個 API。如果使用 UTF-8,'A' 和 'W' API 將相同,並且由於兩者都是可變大小的,因此沒有缺點。儘管大多數 Windows 程式設計師不熟悉 UTF-8,但您可能會看到更多使用非 UNICODE API 的引用。
Win32 API 將其所有需要文字輸入的功能分為兩類。一些函式帶有“A”字尾(表示 ASCII),另一些則帶有“W”字尾(表示寬字元或 Unicode)。這些函式使用宏“UNICODE”進行區分。
#ifdef UNICODE #define MessageBox MessageBoxW #else #define MessageBox MessageBoxA #endif
由於這種區分,當您收到編譯器錯誤時,您將在“MessageBoxW”上收到錯誤,而不是簡單地收到“MessageBox”。在這種情況下,編譯器沒有錯誤。它只是試圖遵循一組複雜的宏。
所有需要字元字串的 Windows 函式都以這種方式定義。如果要在程式中使用 unicode,則需要在包含 windows.h 檔案之前顯式定義 UNICODE 宏。
#define UNICODE #include <windows.h>
此外,其他庫中的某些函式要求您定義宏 _UNICODE。標準庫函式可以透過包含 <tchar.h> 檔案來提供 unicode。因此,要在專案中使用 unicode,您需要在專案中進行以下宣告。
#define UNICODE #define _UNICODE #include <windows.h> #include <tchar.h>
一些標頭檔案包含如下機制,以便當兩個 UNICODE 宏之一被定義時,另一個也會自動被定義。
#ifdef UNICODE
#ifndef _UNICODE
#define _UNICODE
#endif
#endif
#ifdef _UNICODE
#ifndef UNICODE
#define UNICODE
#endif
#endif
如果要編寫一個使用 UNICODE 的庫,那麼在您的標頭檔案中包含此機制可能會有所幫助,這樣其他程式設計師就不必擔心包含這兩個宏。通常情況下,只定義兩個宏中的一個是一個陷阱,所以要注意!
在 C 中,要建立一個寬字元字串,您需要在字串前面加上字母“L”。以下是一個例子
char *asciimessage = "This is an ASCII string."; wchar_t *unicodemessage = L"This is a Wide Unicode string.";
資料型別“TCHAR”定義為,如果未定義 unicode,則為 char 型別,如果定義了 UNICODE(在 tchar.h 中),則為寬型別。為了使字串在 unicode 和非 unicode 之間可移植,我們可以使用 TEXT() 宏自動將字串定義為 unicode 或非 unicode
TCHAR *automessage = TEXT("This message can be either ASCII or UNICODE!");
使用 TCHAR 資料型別和 TEXT 宏是使程式碼在不同環境之間可移植的重要步驟。
此外,TEXT 宏可以寫成
TEXT("This is a generic string");
_T("This is also a generic string");
T("This is also a generic string");
所有這三個語句都是等效的。
TEXT 宏通常這樣定義
#ifdef UNICODE #define TEXT(t) L##t #define _T(t) L##t #define T(t) L##t #else #define TEXT(t) t #define _T(t) t #define T(t) t #endif
- 參見 Unicode
Unicode 字元 0 到 31(U+0000 到 U+001F)屬於 C0 控制和基本拉丁塊。它們都是控制字元。這些字元對應於 ASCII 集的前 32 個字元。
| 程式碼點 | 十進位制等效值 | 名稱 | C 轉義 |
|---|---|---|---|
| U+0000 | 0 | 空字元 | |
| U+0001 | 1 | 報頭開始 | |
| U+0002 | 2 | 文字開始 | |
| U+0003 | 3 | 文字結束 | |
| U+0004 | 4 | 傳輸結束 | |
| U+0005 | 5 | 詢問 | |
| U+0006 | 6 | 確認 | |
| U+0007 | 7 | 響鈴 | '\a' |
| U+0008 | 8 | 退格 | '\b' |
| U+0009 | 9 | 水平製表符 | '\t' |
| U+000A | 10 | 換行符 | '\n' |
| U+000B | 11 | 垂直製表符 | '\v' |
| U+000C | 12 | 換頁符 | '\f' |
| U+000D | 13 | 回車符 | '\r' |
| U+000E | 14 | 換出 | |
| U+000F | 15 | 換入 | |
| U+0010 | 16 | 資料鏈路轉義 | |
| U+0011 | 17 | 裝置控制 1 | |
| U+0012 | 18 | 裝置控制 2 | |
| U+0013 | 19 | 裝置控制 3 | |
| U+0014 | 20 | 裝置控制 4 | |
| U+0015 | 21 | 否定確認 | |
| U+0016 | 22 | 同步空閒 | |
| U+0017 | 23 | 傳輸塊結束 | |
| U+0018 | 24 | 取消 | |
| U+0019 | 25 | 介質結束 | |
| U+001A | 26 | 替換 | |
| U+001B | 27 | 轉義 | |
| U+001C | 28 | 檔案分隔符 | |
| U+001D | 29 | 組分隔符 | |
| U+001E | 30 | 記錄分隔符 | |
| U+001F | 31 | 單元分隔符 |
注意:在 Windows API 中,控制字元的含義與命令列程式中的含義不同!通常,控制字元根本不會被處理,而是顯示為不可列印字元,例如 ExtTextOut() 和所有 GDI 函式。對於 USER 函式,例如 DrawText()、MessageBox() 和多行按鈕,'\n' 將被處理以將文字分成行。對於選單,'\a' 和 '\t' 具有特殊含義並被預處理。要響鈴,'\a' 永遠不會起作用。為此,請使用 Beep() 或 sndPlaySound()。
- 動態連結庫 (DLL)