Unicode与ANSI字符串转换1.jpg
Unicode与ANSI字符串转换2.jpg
Unicode与ANSI字符串转换3.jpg
Unicode与ANSI字符串转换4.jpg
Unicode与ANSI字符串转换5.jpg
Archive for the ‘平台’ Category
Unicode与ANSI字符串转换
星期一, 12 10 月, 2009推荐的字符和字符串处理方式
星期一, 12 10 月, 2009基于本章到目前为止的内容,本节首先要总结开发代码时始终要牢记的几点。接下来要提供一些提示与技巧,帮你更好地处理Unicode和ANSI字符串。你最好现在就将应用程序转换为支持Unicode的形式,即使并不计划立即开始使用Unicode字符。下面是一些应该遵循的基本准则:
开始将文本字符串想象为字符的数组,而不是char或字节的数组。
为文本字符和字符串使用泛型(比如TCHAR/PTSTR)。
为字节、字节指针和数据缓冲区使用显式数据类型(BYTE和PBYTE) 。
为literal字符和字符串使用TEXT或_T宏,但为了保持一致性和更好的可读性,请避免两者混用。
执行全局替换。(例如,用PTSTR替换PSTR)。
修改字符串算术问题。例如,函数经常希望你传给它缓冲区的字符数,而不是字节数。这意味着你应该传入_countof(szBuffer),而不是sizeof(szBuffer)。而且,如果需要为一个字符串分配一个内存块,而且知道字符串中的字符数,那么记住内存是以字节来分配的。这意味着你必须调用malloc(nCharacters * sizeof(TCHAR)),而不是调用malloc(nCharacters)。在前面列出的所有基本准则中,这是最难记住的一条,而且如果出错,编译器不会提供任何警告或错误信息。所以,最好定义一个宏来避免犯错:
#define chmalloc(nCharacters) (TCHAR*)malloc(nCharacters * sizeof(TCHAR)).
避免使用printf系的函数,尤其是不要用%s和%S字段类型来进行ANSI与字符串的相互转换。正确的做法是使用MultiByteToWideChar和WideCharToMultiByte函数,详情参见后面的“Unicode与ANSI字符串转换”一节。
UNICODE和_UNICODE符号要么都指定,要么一个都不指定。
对于字符串处理函数,应该遵循以下基本准则:
始终使用安全的字符串处理函数,比如那些后缀为_s的,或者前缀为StringCch的。后者主要在你想明确控制截断的时候使用;如果不想明确控制截断,则首选前者。
不要使用不安全的C运行库字符串处理函数(参见前面的建议)。一般情况下,你使用或实现的任何缓冲区处理例程都必须获取目标缓冲区的长度作为一个参数。C运行库提供了一系列缓冲区处理替代函数,比如memcpy_s,memmove_s,wmemcpy_s或wmemmove_s。只要定义了__STDC_WANT_SECURE_LIB__符号,所有这些方法都是可用的;CrtDefs.h默认定义了此符号。所以,不要对_STDC_WANT_SECURE_LIB__进行undef。
利用/GS (http://msdn2.microsoft.com/en-us/library/aa290051(VS.71).aspx)和/RTCs编译器标志来自动检测缓冲区溢出。
不要用Kernel32方法来进行字符串处理,比如lstrcat和lstrcpy。
在我们的代码中,需要要比较两种字符串。其中,编程类的字符串包括文件名、路径、XML元素/属性以及注册表项/值等等。对于这些字符串,应使用CompareStringOrdinal来进行比较。因为它非常快,而且不会考虑用户的区域设置。这是完全合理的,因为不管程序在世界上的什么地方运行,这种字符串都是不变的。用户字符串则一般要在用户界面上显示。对于这些字符串,应使用CompareString(Ex)来比较,因为在比较字符串的时候,它会考虑用户的区域设置。
你别无选择:作为专业开发人员,基于不安全的缓冲区处理函数来写代码是不允许的。正是这个原因,本书所有代码都是使用C运行库中的这些更安全的函数来写的。
C运行库中的安全字符串函数
星期一, 12 10 月, 2009ANSI字符和Unicode字符
星期一, 12 10 月, 2009C语言用char数据类型来表示一个8位ANSI字符,Microsoft的C/C++编译器定义了一个内建的数据类型wchar_t,它表示一个16位的Unicode(UTF-16)字符。
因为早期版本的Microsoft编译器没有提供这个内建的数据类型,所以编译器只有在指定了/Zc:wchar_t编译器开关时,才会定义这个数据类型。默认情况下,在VS中新建一个C++项目时,这个编译器开关是指定的。
在编译器内建对wchar_t的支持之前,有一个C头文件定义了一个wchar_t数据类型,如下所示:
typedef unsigned short wchar_t;
为了与C语言稍微有一些区分,Windows开发团队希望定义自己的数据类型。于是,他们在Windows头文件WinNT.h中定义了以下数据类型:
typedef char CHAR;
typedef wchar_t WCHAR;
除此之外,WinNT.h头文件还定义了一系列能为我们提供大量方便的数据类型,可以用它们来处理字符指针和字符串指针。根据是否定义了UNICODE宏,将TCHAR数据类型指定为WCHAR或CHAR类型。
总结:
TCHAR –> 定义了UNICODE宏 –> WCHAR –> wchar_t
TCHAR –> 未定义UNICODE宏 –> CHAR –> char
另:
C运行库针对不属于C++标准一部分的标识符,始终会为它们附加下划线前缀。因此,在C运行库使用UTF-16字符和字符串操作前,定义了_UNICODE宏。
但是,Windows团队并没有这么做。所以,在应用程序中,应确保要么同时定义了UNICODE和_UNICODE,要么一个都不要定义。默认情况下,在VS中新建一个C++项目时,这两个宏都是被定义了的。
监视“上一个错误代码”GetLastError
星期日, 11 10 月, 2009在VS中配置Watch(监视)窗口,让它始终显示线程的上一个错误代码和文本描述。
具体的做法是:在Watch窗口中选择一行,然后输入“$err,hr”。
