分享
 
 
 

补充 - C++字符串完全指引.htm

王朝c/c++·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

写了n年程序,近来在字符串上栽了。:( 认真的研究了一些关于字符串的文章,在此记下。

许多关于字符串的问题,在文章最后的参考文章中,相信有更加深入和精确的描述。不过关于中文的处理,我想先补充一些自己的看法。

背景:WIN32 console程序,使用printf输出字符串。相信许多人都有使用过。

平台:VisualStudio.NET 2003(MFC 7.1)。

MBCS

UNICODE

b2 cc

21 85

A

41 00

41 00

程序段1:使用std::string

#include <string>

{

// NOTE: use s1._Bx._Buf to see the memory

std::string s1 ("蔡"); // b2 cc 00

}

{

std::wstring s1(L"蔡"); // b2 00 cc 00 00 00

}

以上代码,不管使用MBCS还是_UNICODE编译,得到的结果都是一样的。因为string (实际上是basic_string)不会自动进行从MBCS到UNICODE的转换。所以使用printf或者wprintf输出即可。前提当然是你的系统需要支持中文。

让我们把代码修改一下,希望可以输出字符串的内容:

{

std::string s1 ("蔡"); // b2 cc 00

OutputDebugStringA(s1.c_str());

printf(s1.c_str());

}

{

std::wstring s1(L"蔡"); // b2 00 cc 00 00 00

OutputDebugStringW(s1.c_str());

wprintf(s1.c_str());

}

OutputDebugString实际上就是ATLTRACE()最后调用的函数,该函数向VisualStudio的Output窗口输出,而printf和wprintf向console窗口输出。最后的结果如何?OutputDebugStringW输出的是怪字符!!WHY?? s1.c_str()传递给OutputDebugStringW和wprintf不是都是内容相同的LPCWSTR吗?

1)因为OutputDebugStringW的字符串必须是真正UNICODE编码的字符串,而不是所有的const wchar_t*(即LPCWSTR)都可以得到正确结果。在这里s1虽然使用wchar_t类型,但是实际的内容却是MBCS编码。

2)反之亦然:CRT的wprintf只支持MBCS编码的字符串,而不能是UNICODE编码的字符串。在程序段2我们可以看到真正的UNICODE编码的字符串。

这是我多年来的一个误区:wchar_t类型的字符串就是UNICODE字符串。实际应该理解为UNICODE是16位的字符集,可以使用wchar_t类型进行存储。

程序段2:使用CString

请看程序后面的说明。

1. ////////////////// START: compile with _UNICODE ///////////////////

2. {

3. CString s1 ("A"); // 41 00 00 00

4. }

5. {

6. CString s1 (L"A"); // 41 00 00 00

7. }

8. {

9. CString s1 (_T("A")); // 41 00 00 00

10. }

11. {

12. CString s1 ("蔡"); // 21 85 00 00

13. }

14. {

15. CString s1 (L"蔡"); // b2 00 cc 00 00 00

16. }

17. {

18. CString s1 (_T("蔡")); // b2 00 cc 00 00 00

19. }

20. ////////////////// END: compile with _UNICODE ///////////////////

21. ////////////////// START: compile with _MBCS ///////////////////

22. {

23. CString s1 ("A"); // 41 00

24. }

25. {

26. CString s1 (L"A"); // 41 00

27. }

28. {

29. CString s1 (_T("A")); // 41 00

30. }

31. {

32. CString s1 ("蔡"); // b2 cc 00

33. }

34. {

35. CString s1 (L"蔡"); // 32 a8 ac 00

36. }

37. {

38. CString s1 (_T("蔡")); // b2 cc 00

39. }

40. ////////////////// END: compile with _MBCS ///////////////////

1)对于英文字母‘A’,MBCS和UNICODE的结果都是一样的

2)Line 15.

CString s1 (L"蔡"); // b2 00 cc 00 00 00

得到的还是MBCS的字符串,只是增加了0作为trail byte。而不是我理解的UNICODE字符串!这是我多年来的另外一个误区:_T在_UNICODE下转换为L,而L后面的字符串是UNICODE编码。在参考资料MSDN的“TCHAR.H 中的一般文本映射”中(以及MSDN的许多地方),可以看到类似的说明:

一般文本数据类型映射

一般文本数据类型名

未定义 _UNICODE 或 _MBCS

已定义

_MBCS

已定义 _UNICODE

_TCHAR

char

char

wchar_t

_TINT

int

int

wint_t

_TSCHAR

signed char

signed char

wchar_t

_TUCHAR

unsigned char

unsigned char

wchar_t

_TXCHAR

char

unsigned char

wchar_t

_T 或 _TEXT

无效(由预处理器移除)

无效(由预处理器移除)

L(将后面的字符或字符串转换成相应的 Unicode 形式)

实际上L"xxx"只是通知编译器,我们需要的是wchar_t类型的字符串,而不能影响编码。

真正的UNICODE字符串在哪里?

3)Line 12:

等同于 CStringW s1 ("蔡"); // 21 85 00 00

我们看到,得到了真正的UNICODE 字符串。因为CString(在MFC 7.1中,不存在MFC的CString,实际上由ATL::CStringT通过typedef定义而得)的构造函数,在这里实际上是CStringW的构造函数,根据输入的参数是char类型字符串,会自动调用MultiByteToWideChar转换MBCS字符串为UNICODE字符串。

4)相应Line 12,那么Line 35得到的结果32 a8 ac 00是什么?和Line 12类似:

CString构造函数,在这里实际上是CStringA的构造函数,根据输入的参数是wchar_t类型字符串,会自动调用WideCharToMultiByte转换UNICODE字符串为MBCS字符串。但是根据2),我们知道,输入的参数不是UNICODE字符串,只是MBCS的wchar_t类型字符串,所以得到的是错误的编码。

总结以上,可知:

1)CRT不能生成和处理UNICODE类型字符串,对于wchar_t类型字符串,只能处理MBCS编码;

2)VC RunTime中带W后缀的函数,和所有的COM函数,对于wchar_t类型字符串,只能处理UNICODE编码;

3)如果不考虑输出,只是进行拷贝、比较等操作,只要注意_T的含义和字符串的字符类型长度就可以了;但是如果需要输出,必须注意字符串的编码转换。

4)使用UNICODE或者MBCS的编译选项,只是影响字符串的字符类型(自动识别_T,CString等,自动把函数转换为xxxxA()或者xxxxW()),不影响字符串的编码。下表的代码结果不受编译选项影响(这也是编译器处理_T,CString等后的结果):

CStringA s = "xxx"; // 等于 CA2A("xxx")

结果为SBCS(单字节编码)

printf()正确

OutputDebugStringA()正确

CStringW s = "xxx"; // 等于 CA2W("xxx")

结果为UNICODE编码

wprintf()错误

OutputDebugStringW()正确

CStringA s = L"xxx"; // 等于 CW2A(L"xxx")

结果为MBCS编码(可能错误)

printf()错误

OutputDebugStringA()错误

CStringW s = L"xxx"; // 等于 CW2W("xxx")

不改变字符串的编码,仍然是MBCS。

wprintf()正确

OutputDebugStringW()错误

疑问:我认为对于CW2W是由系统编码决定,可以直接得到UNICODE吗?

关于CW2A,如果后面的字符串的确是UNICODE编码,则可以得到正确的相应MBCS编码字符串。实际上,这也是我们要输出UNICODE的方法:

CStringW s = "蔡"; // s 现在是UNICODE编码

// wprintf(s)不正确

CW2A psz(s); // psz现在是s相应的正确的MBCS编码!

printf(psz); // 正确

// All is OK, a little more to say

CA2W wsz(psz); // wsz现在是psz的错误的UNICODE编码,即32 a8 ac 00

推荐参考资料

The Complete Guide to C++ Strings:个人认为很好和很全面的文章

The Complete Guide to C++ Strings, Part I - Win32 Character Encodings

http://www.codeproject.com/string/CPPStringGuide1.asp

The Complete Guide to C++ Strings, Part I - Win32 Character Encodings

http://www.codeproject.com/string/cppstringguide2.asp

这2篇是不错的中文翻译。 :)

C++字符串完全指引之一 —— Win32 字符编码

http://www.vckbase.com/document/viewdoc/?id=1082

C++字符串完全指引之二 —— 字符串封装类

http://www.vckbase.com/document/viewdoc/?id=1096

其它一篇

STL 字符串类与 UNICODE

http://www.vckbase.com/vckbase/default.aspx

当然,少不了MSDN

TCHAR.H 中的一般文本映射

http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/vccore/html/_core_generic.2d.text_mappings_in_tchar..h.asp

建议:最好把整个“国际编程”目录看一次(虽然看完还是糊涂 :) )

http://msdn.microsoft.com/library/CHS/vccore/html/_core_International_Programming_Topics.asp

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有