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

(三) Windows中的Unicode和ANSI函数
 
  从Windows NT开始,所有的Windows版本均使用Unicode构建。所有的Windows核心函数均使用Unicode字符串。如果你调用这些函数时传递了ANSI字符串,函数首先将字符串转换为Unicode编码,然后将编码后的字符串传递给操作系统。如果你想让函数返回ANSI字符串,系统会在Unicode字符串返回之前将其编码为ANSI格式。这些隐藏的转换动作给你的应用程序带来了额外的时间和空间消耗。
  Windows提供的含有字符串参数的函数通常都有两个版本——ANSI和Unicode版本。比如,CreateWindowEx同时兼容Unicode和ANSI字符串,这是借助宏定义实现的,在WinNT.h中可以看到如下代码:

#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif

 
CreateWindowExW接受Unicode编码的字符串,而CreateWindowExA接受ANSI编码的字符串,这两个函数的原型声明如下:

HWND WINAPI CreateWindowExW(
   DWORD dwExStyle,
   PCWSTR pClassName,
// A Unicode string
   PCWSTR pWindowName,
// A Unicode string
   DWORD dwStyle,
   int X,
   int Y,
   int nWidth,
   int nHeight,
   HWND hWndParent,
   HMENU hMenu,
   HINSTANCE hInstance,
   PVOID pParam);

HWND WINAPI CreateWindowExA(
   DWORD dwExStyle,
   PCSTR pClassName,
// An ANSI string
   PCSTR pWindowName,
// An ANSI string
   DWORD dwStyle,
   int X,
   int Y,
   int nWidth,
   int nHeight,
   HWND hWndParent,
   HMENU hMenu,
   HINSTANCE hInstance,
   PVOID pParam);


在程序的源码中是否定义了UNICODE宏决定CreateWindowEx被展开为哪个函数。当使用Visaul Studio创建新项目时,UNICODE宏会被自动定义。因此任何对CreateWindowEx的调用都将默认展开为CreateWindowExW。
  在Windows Vista中,CreateWindowExA只是负责分配内存、将传递给它的ANSI字符串编码为UNICODE格式,并调用CreateWindowExW。当CreateWindowExW返回时,CreateWindowExA释放已分配的内存并将CreateWindowExW返回的句柄返回给主调者。对于那些需要用字符串填充缓冲区的函数,系统必须将Unicode字符转换为非Unicode编码。编码转换带来的时间和空间开销会影响程序的效率。为了获得更好的运行效果,你应该从一开始就使用Unicode编码。同时,Windows已被发现在进行编码转换时可能会发生错误,因此你应该使用Unicode避免这样的转换所产生的bug。
  有些Windows API只是为了和只支持ANSI编码的16位应用程序兼容而被遗留下来,如WinExec和OpenFile。在开发时应当尽量避免调用这些函数。你可以使用CreateProcess和CreateFile代替WinExec和OpenFile。这些函数的问题在于它们只支持ANSI字符串,并且与新的函数相比功能要逊色很多。在Windows Vista下,许多函数都有Unicode和ANSI两个版本,但是,微软已经开始将一些函数设计为只支持Unicode字符串——如ReadDirectoryChangeW和CreateProcessWithLogonW。
  当微软将COM从16位Windows向Win32移植时,所有的COM接口函数被重新定义为只接受Unicode字符串。这是个明智的决定,因为COM主要用于不同的组件之间通信,而Unicode编码则是传递字符串的理想选择。在你的应用中使用Unicode会使与COM的交互更加便捷。
  最后,编译器会把所有的资源编译并输出在二进制文件中。资源中的字符串总是用Unicode编码。在Windows Vista中,如果应用程序没有定义UNICODE宏,系统会做内部编码转换。比如若程序没有定义UNICODE宏并调用了LoadString函数,该调用会被展开为LoadStringA,后者从资源中读取Unicode字符串并用ANSI对其编码,编码后的ANSI字符串会返回给主调程序,这同样涉及到编码转换的时间和空间开销,因此总是使用Unicode是个好主意。

(四) C运行时中的ANSI和Unicode函数
  和Windows所提供的函数类似,C运行时的字符(串)操作函数也包括ANSI版和Unicode版。比如C运行时返回ANSI字符串长度的函数是strlen,而返回Unicode字符串长度的函数则是wcslen。要注意C运行时的这些函数并不像Windows函数那样会自动完成ANSI和Unicode编码的转换,这意味着传递的字符串使用了不同的编码时函数调用会出现问题。
  C运行时的这些函数原型均在String.h中声明。编写同时兼容ansi和unicode编码字符串的代码时,你必须添加Tchar.h头文件,其中包含如下宏:
可以看到编码时我们应该调用_tcslen。如果_UNICODE宏已定义,则展开为wcslen,否则展开为strlen。Visual Studio创建新项目时已默认定义了_UNICODE宏。C运行时库中以前缀下划线标识被修饰部分并非C++标准。为了保持一致性,在你的工程中UNICODE和_UNICODE总是应该同时定义或者都不定义。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值