C++ Builder 的字符串類型、字符類型、字符編碼

C++ Builder 參考手冊(cè) ? C++ Builder 的字符串類型、字符類型、字符編碼


  • 字符變量
  • 字符常數(shù)
  • 字符串常數(shù)
  • 標(biāo)準(zhǔn) C / C++ 字符串變量類型
  • Windows API 字符串變量類型
  • C++ Builder 字符串變量類型
  • UTF-8 / UTF-16 / UTF-32 / ANSI / GBK / BIG5 等編碼轉(zhuǎn)換

一. 字符變量

變量類型 說明
char 一個(gè)字節(jié)的字符變量類型,有符號(hào)或無符號(hào) 8 位整數(shù)【注1】,
UTF-8 或 ANSI / ASCII 編碼 【注2】
wchar_t 寬字符變量類型,2 或 4 個(gè)字節(jié),UTF-16 或 UTF-32 編碼,
操作系統(tǒng) API 函數(shù)的寬字符類型【注3】
char16_t 2 個(gè)字節(jié)的字符變量類型,UTF-16 編碼
char32_t 4 個(gè)字節(jié)的字符變量類型,UTF-32 編碼
_TCHAR C 語言頭文件 <tchar.h> 里面的變量類型,
項(xiàng)目設(shè)置里面的 _TCHAR maps to 選項(xiàng)
可以設(shè)此類型為 wchar_t 或 char
TCHAR Windows API 里面的字符變量類型,與 _TCHAR 類型相同

【注1】char 類型在不同的平臺(tái)里面,可能是有符號(hào)整數(shù) (x86 / x64),也可能是無符號(hào)整數(shù) (ARM / PowerPC)。大多數(shù)編譯器里面的 char 都是 8 位的整數(shù),雖然 C / C++ 標(biāo)準(zhǔn)里面沒有規(guī)定 char 的位數(shù),但是說明了 char 必須支持 UTF-8 編碼 (C++ 14),那么 char 就應(yīng)該是 8 位整數(shù)。

【注2】char 類型的字符編碼,可能是 UTF-8 類型的 (Linux 默認(rèn)編碼 / Windows 10 1903 之后的版本在控制面板里面設(shè)定 UTF-8 編碼,如下面的截圖所示),也可能是 ANSI 編碼 (Windows 到目前為止的所有的版本的默認(rèn)的編碼)。

【注3】wchar_t 類型在不同的平臺(tái)里面,可能是 2 個(gè)字節(jié)的 UTF-16 編碼的字符類型 (Windows),也可能是 4 個(gè)字節(jié)的 UTF-32 編碼的字符類型 (Linux)。

Windows 10 1903 之后版本的控制面板里面的 UTF-8 編碼選項(xiàng),打勾之后,"字符串"、char、std::string 和 AnsiString 都變成了 UTF-8 編碼:

Windows 10 的字符編碼改為 UTF-8 的選項(xiàng)

二. 字符常數(shù)

字符常數(shù) 說明
'c' 單引號(hào)里面只能有一個(gè)字符【注4】,是一個(gè)字符的常數(shù),
這個(gè)常數(shù)的值是一個(gè)整數(shù),int 或 unsigned int 類型【注5】,
等于這個(gè)字符的編碼值,UTF-8 或 ANSI【注6】
L'c' 前綴為大寫英文字母 L 的單引號(hào)里面只能有一個(gè)字符,
是一個(gè)字符的常數(shù),wchar_t 類型的,
數(shù)值等于這個(gè)字符的編碼值,UTF-16 或 UTF-32【注7】
u'c' 前綴為小寫英文字母 u 的單引號(hào)里面只能有一個(gè)字符,
是一個(gè)字符的常數(shù),char16_t 類型的,
數(shù)值等于這個(gè)字符的編碼值,UTF-16編碼【注8】
U'c' 前綴為大寫英文字母 U 的單引號(hào)里面只能有一個(gè)字符,
是一個(gè)字符的常數(shù),char32_t 類型的,
數(shù)值等于這個(gè)字符的編碼值,UTF-32 編碼
_T('c') C 語言頭文件 <tchar.h> 里面的變量類型,
項(xiàng)目設(shè)置里面的 _TCHAR maps to 選項(xiàng)
設(shè)為 wchar_t 或 char 相當(dāng)于 L'c' 或 'c'
_TEXT('c') 與 _T('c') 相同
TEXT('c') Windows API 里面的字符常數(shù),與 _T('c') 相同

【注4】'c' 單引號(hào)里面只能有一個(gè)字符,不限于編碼為 1 個(gè)字節(jié)的字符 (英文字母與數(shù)字等),也可以有超過一個(gè)字節(jié)的編碼的字符,比如漢字等,例如 '漢' 和 '字' 都可以,單引號(hào)的字符并不是 char 類型的,而是 int 或 unsigned 類型的,如果給 char 賦值,高位字節(jié)丟失,只剩下最低位的一個(gè)字節(jié)的值,這種情況,編譯器可能會(huì)給出警告。

【注5】'c' 或 '漢' 這樣的字符常數(shù),是 int 或 unsigned int 類型的,對(duì)于 C++ Builder,如果使用 clang 編譯器,是 int 類型的,如果使用 Borland 編譯器,是 unsigned int 類型的,其他 C/C++ 開發(fā)工具沒有測(cè)試。clang 編譯器超過 1 個(gè)字節(jié)的編碼的字符常數(shù)會(huì)有警告,因?yàn)橥ǔ_@樣的字符要給 char 賦值,會(huì)丟失高位字節(jié)。

【注6】'c' 或 '漢' 這樣的字符常數(shù)的字符編碼,可能是 UTF-8 類型的 (Linux 默認(rèn)編碼 / Windows 10 1903 之后的版本在控制面板里面設(shè)定 UTF-8 編碼,如本文前面 char 類型的備注的截圖所示的參數(shù)位置),也可能是 ANSI 編碼 (Windows 到目前為止的所有的版本的默認(rèn)的編碼)。

【注7】L'c' 或 L'漢' 這樣的字符常數(shù)的字符編碼和 wchar_t 類型相同,可能是 UTF-32 編碼 (Linux),也可能是 UTF-16 編碼 (Windows)。如果是 UTF-16 編碼,存在 2 個(gè) char16_t 字符的編碼 (4 個(gè)字節(jié)的編碼),如果使用的是 Borland 編譯器,丟失第二個(gè) char16_t,只剩下第一個(gè) char16_t。例如 U+1F642 的 Emoji 字符 L'??' 的 UTF-16 編碼為 0xD83D, 0xDE42 兩個(gè) char16_t 字符,Borland 編譯器這個(gè)字符的編碼值只剩下了 0xD83D。如果使用 clang 編譯器,2 個(gè) char16_t 的編碼的字符無法編譯通過,即 L'漢' 可以得到正確的編碼值,L'??' 就無法編譯通過了,這樣的字符需要用字符串處理。

【注8】u'c' 或 u'漢' 這樣的字符常數(shù)為 UTF-16 編碼的,如果這個(gè)字符是 2 個(gè) char16_t 編碼的,例如 U+1F642 的 Emoji 字符 L'??' 的 UTF-16 編碼為 0xD83D, 0xDE42 兩個(gè) char16_t 字符,就無法編譯通過了,這樣的字符需要用字符串處理。

通過以上注釋,字符常數(shù)的總結(jié):

  • UTF-8 或 ANSI 超過 1 個(gè)字節(jié)的編碼要用字符串處理,單個(gè)字符的字符常數(shù)的值超過了 1 個(gè)字節(jié)對(duì)于不同的編譯器的表現(xiàn)不同,可能無法正確處理;
  • UTF-16 編碼的字符如果是由 2 個(gè) char16_t 組成的,不同的編譯器的表現(xiàn)不同,并且都無法正確處理,所以這樣的字符需要用字符串處理;
  • UTF-32 編碼的字符永遠(yuǎn)都是正確的,他們的編碼值就等于 UNICODE 編碼值。

三. 字符串常數(shù)

字符串常數(shù) 說明
"字符串" UTF-8 或 ANSI 編碼的字符串【注9】
L"字符串" 前綴為大寫英文字母 L 的字符串,
UTF-16 或 UTF-32 編碼【注10】
u"字符串" 前綴為小寫英文字母 u 的字符串,UTF-16編碼
U"字符串" 前綴為大寫英文字母 U 的字符串,UTF-32 編碼
_T("字符串") C 語言頭文件 <tchar.h> 里面的變量類型,
項(xiàng)目設(shè)置里面的 _TCHAR maps to 選項(xiàng)
設(shè)為 wchar_t 或 char 相當(dāng)于 L"字符串" 或 "字符串"
_TEXT("字符串") 與 _T("字符串") 相同
TEXT("字符串") Windows API 里面的字符常數(shù),與 _T("字符串") 相同

【注9】"字符串" 這樣的字符串常數(shù)的字符編碼,可能是 UTF-8 類型的 (Linux 默認(rèn)編碼 / Windows 10 1903 之后的版本在控制面板里面設(shè)定 UTF-8 編碼,如本文前面 char 類型的備注的截圖所示的參數(shù)位置),也可能是 ANSI 編碼 (Windows 到目前為止的所有的版本的默認(rèn)的編碼)。

【注10】L"字符串" 這樣的字符串常數(shù)的字符編碼,可能是 2 個(gè)字節(jié)的 UTF-16 編碼的字符類型 (Windows),也可能是 4 個(gè)字節(jié)的 UTF-32 編碼的字符類型 (Linux)。

四. 標(biāo)準(zhǔn) C / C++ 字符串變量類型

變量類型 說明
char * 字符指針,可以用做字符串變量,UTF-8 或 ANSI 編碼【注11】
wchar_t * 寬字符指針,UTF-16 或 UTF-32 編碼【注12】
char16_t * UTF-16 字符指針
char32_t * UTF-32 字符指針
_TCHAR * _TCHAR 字符指針,請(qǐng)參考 _TCHAR 字符變量類型,
在項(xiàng)目設(shè)置里面的 _TCHAR maps to 選項(xiàng)
可以設(shè) _TCHAR 類型為 wchar_t 或 char
TCHAR * Windows API 里面的類型,同 _TCHAR *
char[] 字符數(shù)組,可以用做字符串變量,UTF-8 或 ANSI 編碼【注11】
wchar_t[] 寬字符數(shù)組,UTF-16 或 UTF-32 編碼【注12】
char16_t[] UTF-16 字符數(shù)組
char32_t[] UTF-32 字符數(shù)組
_TCHAR[] _TCHAR 字符數(shù)組,請(qǐng)參考 _TCHAR 字符變量類型,
在項(xiàng)目設(shè)置里面的 _TCHAR maps to 選項(xiàng)
可以設(shè) _TCHAR 類型為 wchar_t 或 char
TCHAR[] Windows API 里面的類型,同 _TCHAR[]
std::string STL 里面的字符串,UTF-8 或 ANSI 編碼【注11】
std::wstring STL 里面的字符串,UTF16 或 UTF32 編碼【注12】
std::u16string STL 里面的字符串,UTF-16 編碼
std::u32string STL 里面的字符串,UTF-32 編碼

【注11】char * / char [] / std::string 這些的字符串的字符編碼,可能是 UTF-8 類型的 (Linux 默認(rèn)編碼 / Windows 10 1903 之后的版本在控制面板里面設(shè)定 UTF-8 編碼,如本文前面 char 類型的備注的截圖所示的參數(shù)位置),也可能是 ANSI 編碼 (Windows 到目前為止的所有的版本的默認(rèn)的編碼)。

【注12】wchar_t * / wchar_t [] / std::wstring 這些字符串的字符編碼,可能是 UTF-16 編碼的字符串 (Windows),也可能是 UTF-32 編碼的字符串 (Linux)。

五. Windows API 字符串變量類型

API 類型 C 語言類型
CHAR char
PCHAR char *
PSTR char *
LPSTR char *
PCSTR const char *
LPCSTR const char *
WCHAR wchar_t
PWCHAR wchar_t *
PWSTR wchar_t *
LPWSTR wchar_t *
PCWSTR const wchar_t *
LPCWSTR const wchar_t *
PTSTR _TCHAR *
LPTSTR _TCHAR *
PCTSTR const _TCHAR *
LPCTSTR const _TCHAR *
BSTR 雖然看上去是 wchar_t *,但不是 C / C++ 的字符串類型,
而是微軟的 COM 的字符串類型,
前 4 個(gè)字節(jié)是長(zhǎng)度,接下來是字符串內(nèi)容,然后是結(jié)束符,
指針指向第一個(gè)字符,而不是內(nèi)存首地址,
所以從指針指向的內(nèi)容來看像是 C 語言的字符串。

六. C++ Builder 字符串變量類型

變量類型 說明
UnicodeString UTF-16 編碼的字符串,
C++ Builder 最常用的字符串類型
UTF8String UTF-8 編碼的字符串
AnsiString ANSI 編碼的字符串,代碼頁為 0 的字符串【注11】,
typedef AnsiStringT<0> AnsiString;
AnsiStringT<CP> 代碼頁為 CP 的字符串,例如:
AnsiStringT<936> 為 GBK 編碼的字符串,
AnsiStringT<950> 為 BIG5 編碼的字符串,AnsiStringT<65001> 為 UTF-8 編碼的字符串
String UNICODE 版本為 UnicodeString;
ANSI 版本為 AnsiString
RawByteString 相當(dāng)于 char * 類型的封裝,
不處理字符編碼,不進(jìn)行編碼轉(zhuǎn)換
ShortString 只能和 AnsiString 之間互相賦值,字符串長(zhǎng)度在 0 到 255 之間,固定占用 256 個(gè)字節(jié)
SmallString<sz> 只能和 AnsiString 之間互相賦值,字符串長(zhǎng)度在 0 到 sz 之間,固定占用 sz + 1 個(gè)字節(jié)
UCS4String UTF-32 / UCS4 編碼,
只用作編碼轉(zhuǎn)換,不能參與字符串運(yùn)算
WideString BSTR 類型的封裝,微軟的 COM 字符串類型

七. UTF-8 / UTF-16 / UTF-32 / ANSI / GBK / BIG5 等編碼轉(zhuǎn)換

1. UTF-8 / UTF-16 / ANSI / GBK / BIG5 等編碼轉(zhuǎn)換

UnicodeString、UTF8String、AnsiString、AnsiStringT<CP> 這些字符串之間互相賦值可以自動(dòng)轉(zhuǎn)碼。

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    UnicodeString    u16s = L"你好,玄坴!";
    UTF8String       u8s  = u16s;
    AnsiStringT<936> gbk  = u8s;
    AnsiStringT<950> big5 = u16s;
    AnsiString       as   = big5;

    Memo1->Lines->Add(u16s);
    Memo1->Lines->Add(u8s );
    Memo1->Lines->Add(gbk );
    Memo1->Lines->Add(big5);
    Memo1->Lines->Add(as  );

    wchar_t *lpU16  = u16s.c_str(); // UTF-16
    char    *lpUTF8 = u8s.c_str();  // UTF-8
    char    *lpGBK  = gbk.c_str();  // GBK
    char    *lpBIG5 = big5.c_str(); // BIG5
    char    *lpANSI = as.c_str();   // ANSI

    Memo1->Lines->Add(L"---");
    Memo1->Lines->Add(lpU16 );
    Memo1->Lines->Add(lpUTF8);
    Memo1->Lines->Add(lpGBK );
    Memo1->Lines->Add(lpBIG5);
    Memo1->Lines->Add(lpANSI);

    UnicodeString     sU16  = lpU16 ; // UTF-16
    UTF8String        sU8   = lpUTF8; // UTF-8
    AnsiStringT<936>  s936  = lpGBK ; // GBK
    AnsiStringT<950>  s950  = lpBIG5; // BIG5
    AnsiString        sANSI = lpANSI; // ANSI

    Memo1->Lines->Add(L"---");
    Memo1->Lines->Add(sU16  );
    Memo1->Lines->Add(sU8   );
    Memo1->Lines->Add(s936  );
    Memo1->Lines->Add(s950  );
    Memo1->Lines->Add(sANSI );
}

在控制面板里面選擇了 UTF-8 編碼,編譯運(yùn)行:

  • 由于 UnicodeString、UTF8String、AnsiString、AnsiStringT<CP> 這些字符串會(huì)自動(dòng)轉(zhuǎn)碼,所以這樣的字符串顯示出來都不亂碼;
  • char * 字符串只有和控制面板的編碼相同時(shí)不會(huì)亂碼,編碼不同會(huì)亂碼;
  • 把 char * 放回對(duì)應(yīng)編碼的字符串類型里面,就不亂碼了,因?yàn)樗麄儠?huì)自動(dòng)轉(zhuǎn)碼。
控制面板里面選擇了 UTF-8 編碼
編碼轉(zhuǎn)換運(yùn)行結(jié)果

在控制面板里面選擇了中文(簡(jiǎn)體,中國(guó)),編譯運(yùn)行:

  • 由于 UnicodeString、UTF8String、AnsiString、AnsiStringT<CP> 這些字符串會(huì)自動(dòng)轉(zhuǎn)碼,所以這樣的字符串顯示出來都不亂碼;
  • char * 字符串只有和控制面板的編碼相同時(shí)不會(huì)亂碼,編碼不同會(huì)亂碼;
  • 把 char * 放回對(duì)應(yīng)編碼的字符串類型里面,就不亂碼了,因?yàn)樗麄儠?huì)自動(dòng)轉(zhuǎn)碼。
控制面板里面選擇了中文(簡(jiǎn)體,中國(guó))
編碼轉(zhuǎn)換運(yùn)行結(jié)果

2. UTF-32 與其他編碼之間轉(zhuǎn)換

由于 Windows 核心都是 UTF-16 編碼的,沒有處理 UTF-32 編碼的能力,如果有 UTF-32 編碼的數(shù)據(jù)需要轉(zhuǎn)成 UTF-16 處理。

由于 UTF-32 編碼和 UCS4 編碼相同,可以用這兩個(gè)函數(shù)來進(jìn)行編碼轉(zhuǎn)換:

UCS4String __fastcall UnicodeStringToUCS4String(const UnicodeString S);
UnicodeString __fastcall UCS4StringToUnicodeString(const UCS4String S);

UCS4String 字符串也沒有處理字符串的能力,只是 UTF-32 字符的動(dòng)態(tài)數(shù)組,只用來編碼轉(zhuǎn)換,這個(gè)字符串類型是這樣定義的:

typedef DynamicArray<UCS4Char> UCS4String;

相關(guān):


C++ Builder 參考手冊(cè) ? C++ Builder 的字符串類型、字符類型、字符編碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容