亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

Windows 編程中的字符編碼

2023-07-20 06:02:45
8
0

經常在寫代碼的時候需要處理寬字符,ASCII 字符,在代碼中看到 wchar、char 等等。一般都是處理一個方法的時候發現需要的是某字符串,然后這邊有什么字符串,之后查一個轉換方法。還有對于 Unicode 、ANSI 這些不太分得清,所以花了一點時間看了一看。做個小結。

編碼介紹

ANSI

ANSI(American National Standards Institute) 其實并不算是一種固定編碼,可以理解為在不同國家,有著不同的解釋。例如在中國大陸,ANSI 編碼指的就是 GBK 編碼,在臺灣地區指的是 BIG5 編碼。所以一個場景下這種編碼是有問題的,比方說一個保存為 ANSI 編碼的文件,在不同區域的系統下,用記事本打開就會有問題,因為對文本的解釋是不同的。例如在中國的系統上保存,其實就是 GBK 編碼,然后在美國的系統上打開,會被當做 ASCII 編碼來解釋,就會出現問題。看不到想要的內容。(注:所以《 Windows 核心編程(第五版)》(下稱《核心編程》)2.1節作者說到:調用 strlen 會返回“以 0 結尾的一個 ANSI 單字節字符數組”中的字符數,這個表述是不準確的,之所以這么說是因為作者所在的國家顯然是 ASCII 編碼,但是拿到中文這里說就不恰當,可以說是作者的鍋也可以說是譯者的鍋。所以此書第二章所有講到 ANSI,都可以理解為 ASCII 編碼)

Unicode

Unicode 標準(使用多字符編碼)解決了 ASCII 編碼這種單字符編碼無法表示一些包含特別多字符的問題。官方的一段解釋 The Unicode Standard provides a unique number for every character, no matter what platform, device, application or language. ,其實就是把每個字符作為一個具體數字 。對于 Unicode 標準,存在多種編碼,例如:UTF-8 編碼,UTF-16 編碼等等。UTF(Unicode Transformation Format),指的是 Unicode 轉換格式。

UTF-8

以下引用《核心編程》原文:

UTF-8 將一些字符編碼為 1 個字節(可以說就是那些 ASCII 字符),一些字符編碼為 2 個字節,一些字符編碼為 3 個字節,一些字符編碼為 4 個字節。根據 Unicode 的數字不同來區分應該編碼為幾個字節,屬于變長字節編碼。這樣的好處是顯而易見的,就是節省空間,壞處也是顯而易見的,處理一些字符編碼比較復雜的文本,顯然效率會差,至少要不斷判斷是幾個字節,計算長度就比較麻煩。

UTF-16

UTF-16 就比較雞賊了,如果細說就要扯到輔助平面和基本文字平面了,感覺意義都不是很大。簡單理解就是一般字符(文字基本都是這個范疇)編碼為 2 個字節,不一般的編碼為 4 個字節(也就是 2 個 2 字節)。關于 UTF-16 連《核心編程》都沒說,可見作者也是非常雞賊了。

UTF-32

UTF-32 這個算是最省事了,把 Unicode 值用 32 位無符號整數表示就得到了 UTF-32 的編碼了。缺點也是顯而易見的,賊占地方。

BOM頭

經常在 Code Page 中看到帶 BOM 頭和不帶 BOM 頭。這個跟編碼的大小端有關。對于這種多個字節的編碼存在一個大小端的問題。如何來區分編碼的大小端。Unicode 標準推薦使用一個 BOM(Byte Order Mark)來做區分。BOM 的字符編碼是0xFEFF,這個叫做零寬無中斷字符,這也解釋了為什么你在文件里邊去掉和添加 BOM 頭都不會影響排版。所以 BOM 頭的存在可以幫助判斷文本的編碼的大小端,如果沒有 BOM 頭的文本,在跨系統使用的時候,編輯器的實現可以做出兩種做法:1. 會根據系統是大小端強行解釋,這樣的問題是一旦兩個系統不一致,看到的內容也就完全不對了;2. 根據里邊的數據,做一個判斷,因為當大端被解釋成小端有可能會出現 Unicode 中不存在的字符(如 BOM 頭這個字符,0xFEFF存在,0xFFEF不存在)。在我看來顯然應該是第一種做法。具體理由按下不表了。

數據類型

char

1 個字節(8 bit)。用來表示 ASCII 編碼。

wchar_t

2 個字節(16 bit)。用來表示 Unicode 字符(UTF-16)。當寫出 wchar_t c = L'A'; 這行代碼的時候,編譯器會把L后邊的東西用 UTF-16 來編碼。值得一提的是wchar_t早期的 Microsoft 編譯器并不支持。在那個上古時期有這樣一個定義 typedef unsigned short wchar_t 。后來支持以后,編譯器搞了一個編譯開關 /Zc:wchar_t,有這個的才在編譯器定義這個數據類型,現在新建項目的時候會默認開啟了。

CHAR、WCHAR

按照《核心編程》的說法:

為了與 C 語言稍微有一些區分,Windows 開發團隊希望定義自己的數據類型。

  • CHAR:typedef char CHAR
  • WCHAR: typedef wchar_t WCHAR
  • 指針:
     
    // Pointer to 8-bit character(s)
    typedef CHAR *PCHAR;
    typedef CHAR *PSTR;
    typedef CONST CHAR *PCSTR
    
    // Pointer to 16-bit character(s)
    typedef WCHAR *PWCHAR;
    typedef WCHAR *PWSTR;
    typedef CONST WCHAR *PCWSTR

TCHAR

TCHAR c = TEXT('A')。這個可以理解為萬能類型,之所以這么說,可以看一下它的定義

#ifdef UNICODE

typedef WCHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
#define __TEXT(quote) L##quote

#else

typedef CHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST CHAR *PCTSTR;
#define __TEXT(quote) quote

#endif

#define TEXT(quote) __TEXT(quote)



 

所以看你的項目是否定義了 UNICODE 宏來決定 TCHAR 的類型,當然這個 UNICODE 宏還會影響 Windows API 調用函數版本的選擇,后邊細說。所以會看到大批文章告訴你解決什么編不過的問題都直接讓你用 TCHAR 和 TEXT()。但我覺得并沒有太大意義,至少我暫時想不到需要這兩個版本都支持的場景。項目使用哪種數據類型明確一點會比較好,會影響到效率,后邊細說。

函數

對于 Windows API 微軟都會提供兩個版本的例如 CreateWindowExWCreateWindowExA,一個是寬字符版本,一個是單字符版本。當然如果你用CreateWindowEx,你會發現再配合 TCHAR 這套,顯然也可以正常使用。

#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#eles
#define CreateWindowEx CreateWindowExA
#endif
 

就是因為這個緣故。所以上邊我說會影響到函數版本的選擇。而效率問題,在 Windows Vista 上(當然可以理解為之后的版本也都如此) A 版本的函數其實只是一個轉換層,將傳入的 ASCII 字符轉換成 Unicode 字符,然后調用 W 版本。所以這中間會有一個分配內存的過程,顯然會有一個效率上的問題。所以其實現在寫代碼,非常推薦統一使用寬字符版本。

另外除了 Windows API 之外,C 運行庫,也有類似的操作。

#ifdef _UNICODE
#define _tcslen wcslen
#eles
#define _tcslen strlen
#endif
 

只不過使用的是 _UNICODE 宏。所以不想讓工程出現編碼的混亂,顯然 UNICODE、_UNICODE 是要成對出現的。事實上,現在用 Visual Studio 新建工程的時候,默認這兩個都會定義上的。

跨平臺的坑

對于 wchar_t 在 Windows 平臺是 UTF-16 編碼,是 2 個字節的長度。而在 Linux 上是 4 個字節的長度,GCC 編譯的時候會用 UTF-32 編碼。這里邊就會有一個不一致。要考慮編碼轉換問題。

最后

至此編程中需要的編碼,大致了解清楚了。Windows 編程中,除非有特殊需要,否則一律使用寬字符是最好的選擇。編碼則選擇 UTF-16 編碼。

0條評論
0 / 1000
Harper
20文章數
0粉絲數
Harper
20 文章 | 0 粉絲
原創

Windows 編程中的字符編碼

2023-07-20 06:02:45
8
0

經常在寫代碼的時候需要處理寬字符,ASCII 字符,在代碼中看到 wchar、char 等等。一般都是處理一個方法的時候發現需要的是某字符串,然后這邊有什么字符串,之后查一個轉換方法。還有對于 Unicode 、ANSI 這些不太分得清,所以花了一點時間看了一看。做個小結。

編碼介紹

ANSI

ANSI(American National Standards Institute) 其實并不算是一種固定編碼,可以理解為在不同國家,有著不同的解釋。例如在中國大陸,ANSI 編碼指的就是 GBK 編碼,在臺灣地區指的是 BIG5 編碼。所以一個場景下這種編碼是有問題的,比方說一個保存為 ANSI 編碼的文件,在不同區域的系統下,用記事本打開就會有問題,因為對文本的解釋是不同的。例如在中國的系統上保存,其實就是 GBK 編碼,然后在美國的系統上打開,會被當做 ASCII 編碼來解釋,就會出現問題。看不到想要的內容。(注:所以《 Windows 核心編程(第五版)》(下稱《核心編程》)2.1節作者說到:調用 strlen 會返回“以 0 結尾的一個 ANSI 單字節字符數組”中的字符數,這個表述是不準確的,之所以這么說是因為作者所在的國家顯然是 ASCII 編碼,但是拿到中文這里說就不恰當,可以說是作者的鍋也可以說是譯者的鍋。所以此書第二章所有講到 ANSI,都可以理解為 ASCII 編碼)

Unicode

Unicode 標準(使用多字符編碼)解決了 ASCII 編碼這種單字符編碼無法表示一些包含特別多字符的問題。官方的一段解釋 The Unicode Standard provides a unique number for every character, no matter what platform, device, application or language. ,其實就是把每個字符作為一個具體數字 。對于 Unicode 標準,存在多種編碼,例如:UTF-8 編碼,UTF-16 編碼等等。UTF(Unicode Transformation Format),指的是 Unicode 轉換格式。

UTF-8

以下引用《核心編程》原文:

UTF-8 將一些字符編碼為 1 個字節(可以說就是那些 ASCII 字符),一些字符編碼為 2 個字節,一些字符編碼為 3 個字節,一些字符編碼為 4 個字節。根據 Unicode 的數字不同來區分應該編碼為幾個字節,屬于變長字節編碼。這樣的好處是顯而易見的,就是節省空間,壞處也是顯而易見的,處理一些字符編碼比較復雜的文本,顯然效率會差,至少要不斷判斷是幾個字節,計算長度就比較麻煩。

UTF-16

UTF-16 就比較雞賊了,如果細說就要扯到輔助平面和基本文字平面了,感覺意義都不是很大。簡單理解就是一般字符(文字基本都是這個范疇)編碼為 2 個字節,不一般的編碼為 4 個字節(也就是 2 個 2 字節)。關于 UTF-16 連《核心編程》都沒說,可見作者也是非常雞賊了。

UTF-32

UTF-32 這個算是最省事了,把 Unicode 值用 32 位無符號整數表示就得到了 UTF-32 的編碼了。缺點也是顯而易見的,賊占地方。

BOM頭

經常在 Code Page 中看到帶 BOM 頭和不帶 BOM 頭。這個跟編碼的大小端有關。對于這種多個字節的編碼存在一個大小端的問題。如何來區分編碼的大小端。Unicode 標準推薦使用一個 BOM(Byte Order Mark)來做區分。BOM 的字符編碼是0xFEFF,這個叫做零寬無中斷字符,這也解釋了為什么你在文件里邊去掉和添加 BOM 頭都不會影響排版。所以 BOM 頭的存在可以幫助判斷文本的編碼的大小端,如果沒有 BOM 頭的文本,在跨系統使用的時候,編輯器的實現可以做出兩種做法:1. 會根據系統是大小端強行解釋,這樣的問題是一旦兩個系統不一致,看到的內容也就完全不對了;2. 根據里邊的數據,做一個判斷,因為當大端被解釋成小端有可能會出現 Unicode 中不存在的字符(如 BOM 頭這個字符,0xFEFF存在,0xFFEF不存在)。在我看來顯然應該是第一種做法。具體理由按下不表了。

數據類型

char

1 個字節(8 bit)。用來表示 ASCII 編碼。

wchar_t

2 個字節(16 bit)。用來表示 Unicode 字符(UTF-16)。當寫出 wchar_t c = L'A'; 這行代碼的時候,編譯器會把L后邊的東西用 UTF-16 來編碼。值得一提的是wchar_t早期的 Microsoft 編譯器并不支持。在那個上古時期有這樣一個定義 typedef unsigned short wchar_t 。后來支持以后,編譯器搞了一個編譯開關 /Zc:wchar_t,有這個的才在編譯器定義這個數據類型,現在新建項目的時候會默認開啟了。

CHAR、WCHAR

按照《核心編程》的說法:

為了與 C 語言稍微有一些區分,Windows 開發團隊希望定義自己的數據類型。

  • CHAR:typedef char CHAR
  • WCHAR: typedef wchar_t WCHAR
  • 指針:
     
    // Pointer to 8-bit character(s)
    typedef CHAR *PCHAR;
    typedef CHAR *PSTR;
    typedef CONST CHAR *PCSTR
    
    // Pointer to 16-bit character(s)
    typedef WCHAR *PWCHAR;
    typedef WCHAR *PWSTR;
    typedef CONST WCHAR *PCWSTR

TCHAR

TCHAR c = TEXT('A')。這個可以理解為萬能類型,之所以這么說,可以看一下它的定義

#ifdef UNICODE

typedef WCHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
#define __TEXT(quote) L##quote

#else

typedef CHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST CHAR *PCTSTR;
#define __TEXT(quote) quote

#endif

#define TEXT(quote) __TEXT(quote)



 

所以看你的項目是否定義了 UNICODE 宏來決定 TCHAR 的類型,當然這個 UNICODE 宏還會影響 Windows API 調用函數版本的選擇,后邊細說。所以會看到大批文章告訴你解決什么編不過的問題都直接讓你用 TCHAR 和 TEXT()。但我覺得并沒有太大意義,至少我暫時想不到需要這兩個版本都支持的場景。項目使用哪種數據類型明確一點會比較好,會影響到效率,后邊細說。

函數

對于 Windows API 微軟都會提供兩個版本的例如 CreateWindowExWCreateWindowExA,一個是寬字符版本,一個是單字符版本。當然如果你用CreateWindowEx,你會發現再配合 TCHAR 這套,顯然也可以正常使用。

#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#eles
#define CreateWindowEx CreateWindowExA
#endif
 

就是因為這個緣故。所以上邊我說會影響到函數版本的選擇。而效率問題,在 Windows Vista 上(當然可以理解為之后的版本也都如此) A 版本的函數其實只是一個轉換層,將傳入的 ASCII 字符轉換成 Unicode 字符,然后調用 W 版本。所以這中間會有一個分配內存的過程,顯然會有一個效率上的問題。所以其實現在寫代碼,非常推薦統一使用寬字符版本。

另外除了 Windows API 之外,C 運行庫,也有類似的操作。

#ifdef _UNICODE
#define _tcslen wcslen
#eles
#define _tcslen strlen
#endif
 

只不過使用的是 _UNICODE 宏。所以不想讓工程出現編碼的混亂,顯然 UNICODE、_UNICODE 是要成對出現的。事實上,現在用 Visual Studio 新建工程的時候,默認這兩個都會定義上的。

跨平臺的坑

對于 wchar_t 在 Windows 平臺是 UTF-16 編碼,是 2 個字節的長度。而在 Linux 上是 4 個字節的長度,GCC 編譯的時候會用 UTF-32 編碼。這里邊就會有一個不一致。要考慮編碼轉換問題。

最后

至此編程中需要的編碼,大致了解清楚了。Windows 編程中,除非有特殊需要,否則一律使用寬字符是最好的選擇。編碼則選擇 UTF-16 編碼。

文章來自個人專欄
文章 | 訂閱
0條評論
0 / 1000
請輸入你的評論
0
0