当前位置: 代码迷 >> 综合 >> 《Windows核心编程》之”Unicode vs ANSI“
  详细解决方案

《Windows核心编程》之”Unicode vs ANSI“

热度:95   发布时间:2024-01-09 07:29:29.0

        《Windows核心编程》第二章专门介绍编程中的字符和字符串编码以及相关库函数,主要涉及”Unicode“和”ANSI“。书上描述的非常透彻,在此,我将它的主要思想精简并概括如下:

一、字符(串)类型

        ANSI和Unicode是两种不同的字符编码方式。ANSI一般以一个字节(8bits)来编码所有的字符,理论上可以表示256种字符;Unicode,一般指UTF-16(Unicode Transformation Format),它用两个字节(16bits)来编码所有的字符,理论上可以表示65536种字符。

        VC++中,char表示ANSI字符类型,占8位;wchat_t表示UTF-16,占16位,它是VC++编译器中的内置类型,对应编译开关为”/Zc:wchar_t“,默认开启。声明Unicode字符和字符串如下:

 

// a 16-bit character
wchar_t c = L'A';// an array up to 99 16-bit characters and a 16-bit terminating zero
wchar_t szBuffer[100] = L"A String";

 

        L是编译器选项,表示Lager,用于通知编译器该字符应当编译为一个Unicode。 sz - string zero,表示以0结尾的字符串。

        此外,WinNT.h中也定义了大写的STRING、CHAR和WCHAR等typedef类型。值得注意的是,它还定义了宏TEXT,该宏可以兼容ANSI和Unicode。

 

// if UNICODE defined, a 16-bit character; else a 8-bit character
TCHAR c = TEXT('A');// if UNICODE defined, an array of a 16-bit character; else a 8-bit character
TCHAR szBuffer[100] = TEXT("A String");


        STRING是对C库中的string的封装,防止缓冲区溢出,如下:

typedef _STRING
{USHORT Length;USHORT MaximumLength;PCHAR  Buffer;
} STRING;

 

 

 

二、Windows API

        大多数Windows API都提供了两个版本,一个接受Unicode,一个接受ANSI。如CreateWindowExW和CreateWindowExA,其中W - wide,A - ANSI。实际调用的时候,我们只调用CreateWindowEx,因为它内部是这样实现的:

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

 

        在 VS Solution 的“属性 - 常规”中切换“字符集”:多字节/Unicode,再观察 “C/C++ - 命令行”中的编译选项:

 多字节版本:

?
/D "_MBCS"

Unicode 版本:        

/D "_UNICODE" /D "UNICODE"

 

        事实上,我们自己在写DLL导出函数的时候,也可以按照上述方法,提供Unicode和ANSI两个版本的导出函数。而且,在实现的时候,只需要实现Unicode版本的函数,而让ANSI版本的函数实现时,先转换入参为Unicode,再调Unicode版本,返回之前再转换回ANSI即可。

 

三、C运行时库的字符(串)函数

        C运行时库也提供了两个版本,如:strlen和wcslen。其中,wc - wchar的头两个字母,s - str,它是后来才添加的,命名规则比较简单,就是在ANSI版本函数前添加前缀wc,并缩写str为s。

        此外,TChar.h中也提供了一套兼容方法:

 

#ifdef _UNICODE
#define _tcslen wcslen
#else
#define _tcslen strlen
#endif


        tc - text char, s - str

 

        注意,它的宏是_UNICODE,多了一个下划线。

 

四、VC的安全字符串函数

        任何修改字符串的函数都存在一个安全隐患:如果目标字符串缓存区不够大,无法容纳所生成的字符串,就会导致内存中的数据被破坏(memory corruption),即缓冲区溢出。为此,微软定义了一套安全的字符串函数,替代C运行库的字符串函数,它们包含在”StrSafe.h“头文件中。

        新函数的命名规则比较简单,就是在原函数的基础上,添加”_s“后缀。s - secure。对比如下:

 

PTSTR _tcscpy (PTSTR strDestination, PCTSTR strSource);
errno_t _tcscpy_s(PTSTR strDestination, size_t numberofCharacters,PCTSTR strSource);


        第二个参数,指定缓冲区大小,它表示的是字符数,可以通过”_countof宏“计算(在stdlib.h中)。注意,sizeof计算的是字节数,_countof计算的字符数,对于Unicode,它一个字符占用两个字节,最好使用_countof。

 

        新函数会检测一些项目,如:指针不为NULL,整数在有效范围内,缓冲区足够大。如果失败,新函数并不会返回,而是直接终止程序,防止被黑。


        此外,还有一批添加”Cch前缀“的字符串函数,它可以提供用户更多控制。Cch - Count of characters。

 

五、ANSI和Unicode转换函数

MultiByteToWideChar和WideCharToMultiByte

 

六、”IsTextUnicode“判断打开的文本是否是Unicode


 

 

        

  相关解决方案