Windows Via C/C++ Part Ⅰ Chapter 2: 字符和字符串(4)

(六) 为什么使用Unicode?

我们极力推荐你在开发应用时选用Unicode编码处理字符(串),因为:

  • Unicode 可以让你轻松的完成应用程序的国际化;
  • Unicode 允许你发布支持所有语言的exe或dll;
  • Unicode 可以改善代码的执行速度和内存使用率。这是因为Windows内部使用Unicode处理一切字符(串),因此当你使用不同的编码时,Windows必须分配额外的内存并进行代码转换;
  • 使用Unicode 可以保证应用程序使用所有的Windows API——一些WinAPI只提供Unicode版本;
  • 使用Unicode 可以使你的应用程序与COM的整合变得更加简捷;
  • 使用Unicode 可以使你的应用程序与.net框架的整合变得更加简捷;
  • 使用Unicode 可以更有效的处理自定义资源中的字符串。

 

(七) 一些操作字符(串)的建议

本节的第一部分列出了开发人员在编写代码时应该牢记的一些准则,接下来是如何更有效的处理Unicode 和 ANSI字符串的建议。即使你不打算马上使用Unicode,让你的应用程序为Unicode做好准备也是个好主意。下面是一些你应该遵循的基本准则:

  • 将字符串视为字符的数组,而不是字节的数组
  • 使用通用类型(如TCHAR/PTSTR)表示字符和字符串
  • 为字节、字节指针和数据缓冲区使用明确的字节类型(如BYTE/PBYTE)
  • 以TEXT或_T宏修饰字符串字面值,不要同时使用TEXT和_T——为了提高代码可读性和可维护性
  • 牢记字符串计数方法。对于要求字符串个数的地方使用_countof,而不是sizeof,后者返回的是字节数
  • 不要使用printf族函数进行ANSI和Unicode编码转换,你应该使用MultiByteToWideChar和WideCharToMultiByte
  • 记住要么同时定义_UNICODE和UNICODE,要么都不定义

对字符串操作函数,建议如下:

  • 总是使用字符串安全函数,当需要截断处理时使用StringCch开头的函数,否则使用_s结尾的函数
  • 不要使用CRT提供的不安全的字符串操作函数,更进一步,不要使用那些不接受目标缓冲区大小为参数的所有函数。CRT提供了一些处理内存的安全函数,如memcpy_s、memmove_s、wmemcpy_s以及wmemove_s,这些函数在宏__STDC_WANT_SECURE_LIB__定义后才有效,__STDC_WANT_SECURE_LIB__默认定义在CrtDefs.h中,所以千万不要#undef这个宏
  • 打开/GS和/RTCs编译开关以自动检测缓冲区溢出
  • 不要使用Kernel32输出的字符串函数如lstrcat和lstrcpy——它们是不安全的
  • 在代码通常需要比较两种类型的字符串,一是Programmatic strings(这个怎么翻译呢?),包括文件名、路径、xml元素和属性、注册表键/值,对于这些字符串应该使用CompareStringOrdinal,因为它并不考虑当前用户所在地区因此速度很快。而出现在用户接口界面的用户字符串则应该使用考虑了本地语言环境的CompareString(Ex)比较

作为专业的开发人员,你必须将代码构建在缓冲区安全的基础之上,这也是本书中所有代码都依赖于安全字符串函数的原因。

 

(八) Unicode和ANSI字符串的转换

[文中ANSI可以替换为任意多字节编码集(multi-byte character sets)]

把ANSI转换为Unicode编码时要用到MultiByteToWideChar函数,声明如下:

参数uCodePage表示pMultiByteStr字符串使用的编码代码页,dwFlags用于是否区别重音等额外控制,一些将其设置为0既可。pMultiByteStr指向待转换的字符串,cbMultiByte是其大小(以字节数目计),如果将其设为-1,函数将自动检测pMultiByteStr所指字符串的大小。转换产生的Unicode版本字符串将写入pWideCharStr指向的缓冲区中,cchWideChar指示该缓冲区的大小,如果该参数被设置为0,函数并不执行转换,仅仅返回pWideCharStr指向的缓冲区存储转换结果所需的最小字符数目(包括'/0'结束符)。调用该函数完成转换的一般步骤如下:

  1. 调用MultiByteToWideChar,向cchWideChar传递0值
  2. 根据MultiByteToWideChar的返回结果rc分配pWideCharStr指向的缓冲区,其大小是rc * sizeof(wchar_t)
  3. 再次调用MultiByteToWideChar,使用上面得到的结果作为cchWideChar参数
  4. ok,调用成功

将Unicode字符串转换为ANSI编码时,需要调用函数WideCharToMultiByte,声明如下:

uCodePage表示转换后的字符串编码所在代码页,dwFlags设置为0既可。pWideCharStr指向待转换的字符串,cchWideChar为其字符数目,如果设置为-1函数将自动计算该值。转换后的字符串将写入pMultiByteStr指向的缓冲区中,cbMultiByte提供了该缓冲区的大小(以字节计)。向该参数传0时函数返回pMultiByteStr完成转换所需的最小字节数目(和上面的讨论类似)。

调用WideCharToMultiByte时,待转换的Unicode字符串中的某些字符可能在uCodePage中无定义(Unicode中的字符数目要远远大于其它大多数编码所表示的字符数),此时可以通过pDefaultChar指定转换后的字符串的替代字符,如果该参数为NULL,则使用系统默认的替代字符(通常是问号)。pfUsedDefaultChar参数是输出型参数,函数调用完成后假如其指向的值为TRUE,表示转换遇到了uCodePage中无定义的Unicode字符,FALSE则表示转换完全成功。

你可以使用WideCharToMultiByte和MultiByteToWideChar创建同一函数的Unicode和ANSI版本。比如当你想在dll中提供一个用于反转字符串的函数,其Unicode版本可能是下面这样:

当你需要编写其ANSI版本时,你只需将ansi参数使用MultiByteToWideChar转换成Unicode编码后再调用该函数的Unicode版本,然后再将返回的Unicode字符串用WideCharToMultiByte转换为ANSI编码,如下:

最后在你的dll中使用以下语句完成定义:

   

[原文中接下来讲述了如何使用IsTextUnicode函数判断指定的缓冲区内文本是否为Unicode格式,由于这种方法并不可靠,因此不再翻译,感兴趣的朋友可以查阅msdn获得帮助]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值