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

C++ Builder 參考手冊 ? 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 一個字節(jié)的字符變量類型埂软,有符號或無符號 8 位整數(shù)【注1】锈遥,
UTF-8 或 ANSI / ASCII 編碼 【注2】
wchar_t 寬字符變量類型,2 或 4 個字節(jié)勘畔,UTF-16 或 UTF-32 編碼所灸,
操作系統(tǒng) API 函數(shù)的寬字符類型【注3】
char16_t 2 個字節(jié)的字符變量類型,UTF-16 編碼
char32_t 4 個字節(jié)的字符變量類型咖杂,UTF-32 編碼
_TCHAR C 語言頭文件 <tchar.h> 里面的變量類型庆寺,
項目設(shè)置里面的 _TCHAR maps to 選項
可以設(shè)此類型為 wchar_t 或 char
TCHAR Windows API 里面的字符變量類型,與 _TCHAR 類型相同

【注1】char 類型在不同的平臺里面诉字,可能是有符號整數(shù) (x86 / x64)懦尝,也可能是無符號整數(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 類型在不同的平臺里面,可能是 2 個字節(jié)的 UTF-16 編碼的字符類型 (Windows)权谁,也可能是 4 個字節(jié)的 UTF-32 編碼的字符類型 (Linux)剩檀。

Windows 10 1903 之后版本的控制面板里面的 UTF-8 編碼選項,打勾之后旺芽,"字符串"沪猴、char康二、std::string 和 AnsiString 都變成了 UTF-8 編碼:

Windows 10 的字符編碼改為 UTF-8 的選項

二. 字符常數(shù)

字符常數(shù) 說明
'c' 單引號里面只能有一個字符【注4】焕参,是一個字符的常數(shù)葛菇,
這個常數(shù)的值是一個整數(shù)痹扇,int 或 unsigned int 類型【注5】,
等于這個字符的編碼值担租,UTF-8 或 ANSI【注6】
L'c' 前綴為大寫英文字母 L 的單引號里面只能有一個字符砸民,
是一個字符的常數(shù),wchar_t 類型的奋救,
數(shù)值等于這個字符的編碼值阱洪,UTF-16 或 UTF-32【注7】
u'c' 前綴為小寫英文字母 u 的單引號里面只能有一個字符,
是一個字符的常數(shù)菠镇,char16_t 類型的,
數(shù)值等于這個字符的編碼值承璃,UTF-16編碼【注8】
U'c' 前綴為大寫英文字母 U 的單引號里面只能有一個字符利耍,
是一個字符的常數(shù),char32_t 類型的盔粹,
數(shù)值等于這個字符的編碼值隘梨,UTF-32 編碼
_T('c') C 語言頭文件 <tchar.h> 里面的變量類型,
項目設(shè)置里面的 _TCHAR maps to 選項
設(shè)為 wchar_t 或 char 相當(dāng)于 L'c' 或 'c'
_TEXT('c') 與 _T('c') 相同
TEXT('c') Windows API 里面的字符常數(shù)舷嗡,與 _T('c') 相同

【注4】'c' 單引號里面只能有一個字符轴猎,不限于編碼為 1 個字節(jié)的字符 (英文字母與數(shù)字等),也可以有超過一個字節(jié)的編碼的字符进萄,比如漢字等捻脖,例如 '漢' 和 '字' 都可以,單引號的字符并不是 char 類型的中鼠,而是 int 或 unsigned 類型的可婶,如果給 char 賦值,高位字節(jié)丟失援雇,只剩下最低位的一個字節(jié)的值矛渴,這種情況,編譯器可能會給出警告惫搏。

【注5】'c' 或 '漢' 這樣的字符常數(shù)具温,是 int 或 unsigned int 類型的,對于 C++ Builder筐赔,如果使用 clang 編譯器铣猩,是 int 類型的,如果使用 Borland 編譯器川陆,是 unsigned int 類型的剂习,其他 C/C++ 開發(fā)工具沒有測試蛮位。clang 編譯器超過 1 個字節(jié)的編碼的字符常數(shù)會有警告,因為通常這樣的字符要給 char 賦值鳞绕,會丟失高位字節(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 個 char16_t 字符的編碼 (4 個字節(jié)的編碼)冒签,如果使用的是 Borland 編譯器,丟失第二個 char16_t钟病,只剩下第一個 char16_t萧恕。例如 U+1F642 的 Emoji 字符 L'??' 的 UTF-16 編碼為 0xD83D, 0xDE42 兩個 char16_t 字符,Borland 編譯器這個字符的編碼值只剩下了 0xD83D肠阱。如果使用 clang 編譯器票唆,2 個 char16_t 的編碼的字符無法編譯通過,即 L'漢' 可以得到正確的編碼值屹徘,L'??' 就無法編譯通過了走趋,這樣的字符需要用字符串處理。

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

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

  • UTF-8 或 ANSI 超過 1 個字節(jié)的編碼要用字符串處理拙寡,單個字符的字符常數(shù)的值超過了 1 個字節(jié)對于不同的編譯器的表現(xiàn)不同授滓,可能無法正確處理;
  • UTF-16 編碼的字符如果是由 2 個 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> 里面的變量類型,
項目設(shè)置里面的 _TCHAR maps to 選項
設(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 個字節(jié)的 UTF-16 編碼的字符類型 (Windows)乡翅,也可能是 4 個字節(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 字符指針,請參考 _TCHAR 字符變量類型靶累,
在項目設(shè)置里面的 _TCHAR maps to 選項
可以設(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ù)組争舞,請參考 _TCHAR 字符變量類型凛忿,
在項目設(shè)置里面的 _TCHAR maps to 選項
可以設(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 個字節(jié)是長度,接下來是字符串內(nèi)容咒劲,然后是結(jié)束符顷蟆,
指針指向第一個字符诫隅,而不是內(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 * 類型的封裝,
不處理字符編碼绕辖,不進行編碼轉(zhuǎn)換
ShortString 只能和 AnsiString 之間互相賦值摇肌,字符串長度在 0 到 255 之間,固定占用 256 個字節(jié)
SmallString<sz> 只能和 AnsiString 之間互相賦值仪际,字符串長度在 0 到 sz 之間围小,固定占用 sz + 1 個字節(jié)
UCS4String UTF-32 / UCS4 編碼,
只用作編碼轉(zhuǎ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> 這些字符串之間互相賦值可以自動轉(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 編碼,編譯運行:

  • 由于 UnicodeString挣输、UTF8String纬凤、AnsiString、AnsiStringT<CP> 這些字符串會自動轉(zhuǎn)碼撩嚼,所以這樣的字符串顯示出來都不亂碼停士;
  • char * 字符串只有和控制面板的編碼相同時不會亂碼,編碼不同會亂碼完丽;
  • 把 char * 放回對應(yīng)編碼的字符串類型里面向瓷,就不亂碼了,因為他們會自動轉(zhuǎn)碼舰涌。
控制面板里面選擇了 UTF-8 編碼
編碼轉(zhuǎn)換運行結(jié)果

在控制面板里面選擇了中文(簡體猖任,中國),編譯運行:

  • 由于 UnicodeString瓷耙、UTF8String朱躺、AnsiString刁赖、AnsiStringT<CP> 這些字符串會自動轉(zhuǎn)碼,所以這樣的字符串顯示出來都不亂碼长搀;
  • char * 字符串只有和控制面板的編碼相同時不會亂碼宇弛,編碼不同會亂碼;
  • 把 char * 放回對應(yīng)編碼的字符串類型里面源请,就不亂碼了枪芒,因為他們會自動轉(zhuǎn)碼。
控制面板里面選擇了中文(簡體谁尸,中國)
編碼轉(zhuǎn)換運行結(jié)果

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

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

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

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

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

typedef DynamicArray<UCS4Char> UCS4String;

相關(guān):


C++ Builder 參考手冊 ? C++ Builder 的字符串類型、字符類型皮胡、字符編碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痴颊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子屡贺,更是在濱河造成了極大的恐慌蠢棱,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烹笔,死亡現(xiàn)場離奇詭異,居然都是意外死亡抛丽,警方通過查閱死者的電腦和手機谤职,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亿鲜,“玉大人允蜈,你說我怎么就攤上這事≥锪” “怎么了饶套?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長垒探。 經(jīng)常有香客問我妓蛮,道長,這世上最難降的妖魔是什么圾叼? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任蛤克,我火速辦了婚禮捺癞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘构挤。我一直安慰自己髓介,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布筋现。 她就那樣靜靜地躺著唐础,像睡著了一般。 火紅的嫁衣襯著肌膚如雪矾飞。 梳的紋絲不亂的頭發(fā)上一膨,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機與錄音凰慈,去河邊找鬼汞幢。 笑死,一個胖子當(dāng)著我的面吹牛微谓,可吹牛的內(nèi)容都是我干的森篷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼豺型,長吁一口氣:“原來是場噩夢啊……” “哼仲智!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姻氨,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤钓辆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后肴焊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體前联,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年娶眷,在試婚紗的時候發(fā)現(xiàn)自己被綠了似嗤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡届宠,死狀恐怖烁落,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情豌注,我是刑警寧澤伤塌,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站轧铁,受9級特大地震影響每聪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一熊痴、第九天 我趴在偏房一處隱蔽的房頂上張望他爸。 院中可真熱鬧,春花似錦果善、人聲如沸诊笤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讨跟。三九已至,卻和暖如春鄙煤,著一層夾襖步出監(jiān)牢的瞬間晾匠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工梯刚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凉馆,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓亡资,卻偏偏與公主長得像澜共,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锥腻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容