解惑宽字符&&窄字符

hunterzone 2013-02-18 06:50:49

char wchar_t TCHAR
LPSTR LPWSTR LPTSTR
LPCSTR LPCWSTR LPCTSTR
std::string std::wstring CString

不知道大家曾经是否跟我一样对宽字符和窄字符的使用有许多困惑,此贴将将全面解惑宽字符和窄字符的应用,欢迎大家一块讨论!
...全文
3762 54 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
54 条回复
切换为时间正序
请发表友善的回复…
发表回复
hunterzone 2013-05-14
  • 打赏
  • 举报
回复
wcstombs && wcstombs_s 和 mbstowcs && mbstowcs_s wcstombs的定义:

/**
 * @param [in] _MaxCount 限制取出_Source中字符的个数
 * @retval 返回转换的字符的个数,包括对结束符的计算
 */
size_t __cdecl wcstombs(char* _Dest, const wchar_t* _Source, size_t _MaxCount);
wcstombs_s的定义:

/**
 * @param [out] _PtNumOfCharConverted 返回转换的字符的个数,包括对结束符的计算
 * @param [out] _Dst 转换字符存放的目的地址
 * @param [in] _DstSizeInBytes 限制取出_Src中字符的个数,同时也限制为_Dst分配的缓存空间
 * @param [in] _Src 要转换的字符
 * @param [in] _MaxCountInBytes 限制取出_Src中字符的个数
 * @retval 返回错误号,为0则表示转换成功
 */
errno_t __cdecl wcstombs_s(size_t* _PtNumOfCharConverted, char* _Dst, size_t _DstSizeInBytes,  const wchar_t* _Src, size_t _MaxCountInBytes);
函数wcstombs_s中参数_DstSizeInBytes起到的作用:对目的地址_Dst分配的缓存空间的限制,若sizeof(_Dst)/sizeof(char) < _DstSizeInBytes,则会提示异常;同时也限制从_Src取出的个数,至于确定取_Src中字符的个数,先是选择_DstSizeInBytes和_MaxCountInBytes中较小的值minNum,然后如果minNum小于wcslen(_Src),则从中取出minNum个字符,再判断_DstSizeInBytes < (minNum + 1),为true则出断言。 所以一般的形式为这样:

		wcstombs_s(_PtNumOfCharConverted, _Dst, wcslen(_Src) + 1, _Src, _TRUNCATE);
		mbstowcs_s(_PtNumOfCharConverted, _Dst, strlen(_Src) + 1, _Src, _TRUNCATE);
wcstombs_s、wcstombs和mbstowcs_s、mbstowcs都是调用的WideCharToMultiByte和MultiByteToWideChar。这里是否可以看成是对WideCharToMultiByte和MultiByteToWideChar的封装使用?
hunterzone 2013-05-14
  • 打赏
  • 举报
回复
没有翻阅过这方面的标准。。有明显的区别规定?这个还真不知道。。
飞天御剑流 2013-05-14
  • 打赏
  • 举报
回复
引用 50 楼 hunter_wwq 的回复:
c标准库中的宽窄转换主要用到的函数是sprintf && sprintf_s 和swprintf && swprintf_s。那么sprintf和sprintf_s的区别分析如下: sprintf定义:

/**
 * @param [out] _Dest 输出的目的地址
 * @param [in] _Format 输出格式
 * @param [in] ... 参数列表
 * @retval 返回输出字符的个数
 */
int __cdecl sprintf(char* _Dest, const char* _Format, ...);
sprintf_s定义:

/**
 * @param [out] _DstBuf 输出的目的地址
 * @param [in] _SizeInBytes 限制按照输出格式_Format转换后的字符个数,同时也限制为_DstBuf分配的缓存空间
 * @param [in] _Format 输出格式
 * @param [in] ... 参数列表
 * @retval 返回输出字符的个数
 */
int __cdecl sprintf_s(char* _DstBuf, size_t _SizeInBytes, const char* _Format, ...);
函数sprintf和sprintf_s的区别:sprintf_s函数多了一个对目的地址分配的空间和转换字符的个数的限制。例:

ASSERT((sizeof(tranStr)/sizeof(char)) <= _SizeInBytes);
ASSERT((sizeof(_DstBuf)/sizeof(char)) >= _SizeInBytes);
首先判断的是按照输出格式转换的字符串tranStr的个数是否小于等于SizeInBytes,若否,则弹出断言:Buffer to small。可见,在根据_Format进行字符转换时所分配的临时存储空间是由_SizeInBytes来指定的。然后对输出的目的地址_DstBuf的空间大小进行判断,判断其大小是否大于等于_SizeInButes,若否,则可能会出现误用非法空间的可能。不过sprintf_s都为其做了安全处理。所以总的来说,用sprintf_s比用sprintf更安全。
你翻阅过标准没有?没有就不要随意写什么“c标准库”啥啥啥的。
hunterzone 2013-05-14
  • 打赏
  • 举报
回复
sprintf在对宽窄字符之间的转换的用法在于: 转换窄字符的用法:

char _Dest[100];
sprintf_s(_Dest, 100, "%s", "ANSII STR");
其中转换格式必须是小写s; 转换宽字符的用法:

sprintf_s(_Dest, 100, "%S", L"UNICODE STR");
其中转换格式必须是大写S;对比例子:

sprintf_s(_Dest, 100, "%s_%S", "ANSII STR", L"UNICODE STR");
同样,swprintf和swprintf_s的用法:

wchar_t _Dest[100];
swprintf_s(_Dest, 100, L”%s_%S”, L”UNICODE STR”, “ANSII STR”);
hunterzone 2013-05-14
  • 打赏
  • 举报
回复
c标准库中的宽窄转换主要用到的函数是sprintf && sprintf_s 和swprintf && swprintf_s。那么sprintf和sprintf_s的区别分析如下: sprintf定义:

/**
 * @param [out] _Dest 输出的目的地址
 * @param [in] _Format 输出格式
 * @param [in] ... 参数列表
 * @retval 返回输出字符的个数
 */
int __cdecl sprintf(char* _Dest, const char* _Format, ...);
sprintf_s定义:

/**
 * @param [out] _DstBuf 输出的目的地址
 * @param [in] _SizeInBytes 限制按照输出格式_Format转换后的字符个数,同时也限制为_DstBuf分配的缓存空间
 * @param [in] _Format 输出格式
 * @param [in] ... 参数列表
 * @retval 返回输出字符的个数
 */
int __cdecl sprintf_s(char* _DstBuf, size_t _SizeInBytes, const char* _Format, ...);
函数sprintf和sprintf_s的区别:sprintf_s函数多了一个对目的地址分配的空间和转换字符的个数的限制。例:

ASSERT((sizeof(tranStr)/sizeof(char)) <= _SizeInBytes);
ASSERT((sizeof(_DstBuf)/sizeof(char)) >= _SizeInBytes);
首先判断的是按照输出格式转换的字符串tranStr的个数是否小于等于SizeInBytes,若否,则弹出断言:Buffer to small。可见,在根据_Format进行字符转换时所分配的临时存储空间是由_SizeInBytes来指定的。然后对输出的目的地址_DstBuf的空间大小进行判断,判断其大小是否大于等于_SizeInButes,若否,则可能会出现误用非法空间的可能。不过sprintf_s都为其做了安全处理。所以总的来说,用sprintf_s比用sprintf更安全。
youyou1912 2013-05-09
  • 打赏
  • 举报
回复
windows核心编程第一章
hunterzone 2013-05-09
  • 打赏
  • 举报
回复
之前一直在忙着项目开发,现在总算是能够腾出时间来总结一些一直存在的疑惑。还是接着把这个帖子结完,希望各位还是能够互相讨论一下,互相指点一下,只有在讨论中才能够进步。。 现在讲到宽字符与窄字符的相互转换,我准备以这样来分开讲:C标准库中的宽窄转换,windows中的宽窄转换,C++中的宽窄转换,最后再讲一些COM开发中的宽窄转换! 先讲C标准库中的宽窄转换!
china_jeffery 2013-02-26
  • 打赏
  • 举报
回复
引用 42 楼 zhao4zhong1 的回复:
C/C++ code?1234char c='A';//内存中对应字节41wchar_t wc=L'啊';//内存中对应字节4A 55char cs[]="AB啊";//内存中对应字节41 42 B0 A1 00 (GBK编码时)可见窄字符中文字符也是两个字节wchar_t ws[]=L"AB啊";//内存中对应字节41 00 42 00 4A 55 00 00 ……
char是可以用一个字节表示就用一个字节表示,否则就用多个字节表示。 wchar_t 一律用2个字节来表示
赵4老师 2013-02-22
  • 打赏
  • 举报
回复
VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。) 想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单! 指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认: 有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物; 而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。 这辈子不看内存地址和内存值;只画链表、指针示意图,画堆栈示意图,画各种示意图,甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗?本人深表怀疑! 这辈子不种麦不收麦不将麦粒拿去磨面;只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头,压面条,烤面包,……能从本质上理解面粉、理解面食吗?本人深表怀疑!! 提醒: “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 (Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。) 想要从本质上理解C指针,必须学习C和汇编的对应关系。” 不是一回事! 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实! 有人说一套做一套,你相信他说的还是相信他做的? 其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗? 不要写连自己也预测不了结果的代码! 电脑内存只是一个一维二进制字节数组及其对应的二进制地址; 人脑才将电脑内存中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、……
hunterzone 2013-02-22
  • 打赏
  • 举报
回复
引用 38 楼 zhao4zhong1 的回复:
VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo D……
多谢赵老师指点!!!
hunterzone 2013-02-22
  • 打赏
  • 举报
回复
引用 44 楼 qq120848369 的回复:
宽字符就是unicode... 除了宽的就是窄的? unicode注意序列化与网络传输时候考虑本机字节序.
你指的是高8位和低8位的排序吗?
qq120848369 2013-02-22
  • 打赏
  • 举报
回复
宽字符就是unicode... 除了宽的就是窄的? unicode注意序列化与网络传输时候考虑本机字节序.
ningbinzhang 2013-02-22
  • 打赏
  • 举报
回复
引用 41 楼 zhao4zhong1 的回复:
引用 39 楼 ningbinzhang 的回复:引用 30 楼 zhao4zhong1 的回复:一言以蔽之,窄字符就是用一个字节表示一个字符,宽字符就是用≥2个字节表示一个字符。 这个不适用于非英文字符,窄字符中文字符也是两个字节 谢谢斧正!
赵老师果然神速,佩服佩服
赵4老师 2013-02-22
  • 打赏
  • 举报
回复
char c='A';//内存中对应字节41
wchar_t wc=L'啊';//内存中对应字节4A 55
char cs[]="AB啊";//内存中对应字节41 42 B0 A1 00 (GBK编码时)可见窄字符中文字符也是两个字节
wchar_t ws[]=L"AB啊";//内存中对应字节41 00 42 00 4A 55 00 00
赵4老师 2013-02-22
  • 打赏
  • 举报
回复
引用 39 楼 ningbinzhang 的回复:
引用 30 楼 zhao4zhong1 的回复:一言以蔽之,窄字符就是用一个字节表示一个字符,宽字符就是用≥2个字节表示一个字符。 这个不适用于非英文字符,窄字符中文字符也是两个字节
谢谢斧正!
Kaile 2013-02-22
  • 打赏
  • 举报
回复
ningbinzhang 2013-02-22
  • 打赏
  • 举报
回复
引用 30 楼 zhao4zhong1 的回复:
一言以蔽之,窄字符就是用一个字节表示一个字符,宽字符就是用≥2个字节表示一个字符。
这个不适用于非英文字符,窄字符中文字符也是两个字节
hunterzone 2013-02-21
  • 打赏
  • 举报
回复
引用 30 楼 zhao4zhong1 的回复:
一言以蔽之,窄字符就是用一个字节表示一个字符,宽字符就是用≥2个字节表示一个字符。
可能只有像您这样一等一的高手已经经历了从无到有,再从有到无的境界,像我等小辈还没这种深度哇。。
hunterzone 2013-02-21
  • 打赏
  • 举报
回复
引用 29 楼 zhangwuji156 的回复:
其实,在C++ builder里,用的时候直接就是AnsiString/WideString 而在VC里,编译器很"人性化"的 #ifdef UNICODE typedef CString CStringW #else typedef CString CStringA 使一般的用户不用关心到底用的是哪个string,以至于用了很久,都弄不明白其中的区别.
确实,正因为微软仅仅只对UNICODE和ANSI一部分处理操作进行了方便设计使用,而还有一大部分并未设计到位,所以在进行很多关于UNICODE和ANSI操作的时候相当困惑,只有弄清楚了字符串的来龙去脉,才不会对这个有困惑了
赵4老师 2013-02-21
  • 打赏
  • 举报
回复
一言以蔽之,窄字符就是用一个字节表示一个字符,宽字符就是用≥2个字节表示一个字符。
加载更多回复(33)

65,189

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧