当前位置:C++技术网 > 资讯 > 设置字符集的UNICODE和_UNICODE宏的问题分析

设置字符集的UNICODE和_UNICODE宏的问题分析

更新时间:2015-06-26 23:51:35浏览次数:1+次

    设置项目的字符集所涉及到的UNICODE和_UNICODE宏的相关问题的说明分析,理解这个对于字符集就不在害怕了。
    在tchar.h头文件中,定义了宏_UNICODE。
    根据是否定义_UNICODE来判断使用了Unicode字符集,进而包含对应的字符集头文件,以及设定对应的函数版本。并定义__T(x)、_T(x)、_TEXT(x)宏方便使用字符串,而不用管是使用说明版本的函数和字符集。

    节选定义部分如下:

#ifdef  _UNICODE /* 定义了 _UNICODE */
#include <wchar.h>
#define _TEOF    WEOF
#define __T(x)   L ## x

#define _tmain    wmain
#define _tWinMain wWinMain

#define _tprintf wprintf
#define _tscanf         wscanf
#define _gettc          getwc

#define _tcstod     wcstod
#define _tcstol     wcstol
#define _tcstoul    wcstoul

#define _tfopen     _wfopen

#define _tcsclen        wcslen

#endif
#else   /* 没定义 _UNICODE */
#include <string.h>

#define _TEOF       EOF
#define __T(x)      x

#define _tmain      main
#define _tWinMain   WinMain

#define _tprintf        printf

#endif  /* 结束 */

#define _T(x)       __T(x)
#define _TEXT(x)    __T(x)

    然而在windows.h头文件中包含的winuser.h头文件中,定义了Windows中使用的一些函数如MessageBox函数的ANSII版本和Unicode版本。

    定义MessageBox函数版本如下:
#ifdef UNICODE
 #define MessageBox  MessageBoxW
 #else
 #define MessageBox  MessageBoxA
 #endif

    从这里看出,这里定义的是UNICODE,而不是前面的_UNICODE宏。在VC6.0和VS中,如果要正常使用宏_T同时也要使用Windows中的函数,那么需要同时设置预处理器定义(Preprocessor definitions)为UNICODE和_UNICODE,或者设置字符集,会自动将两者设置上。建议使用设置字符集,而不要用预处理器定义。如下图所示。

设置字符集图预处理器指令设置字符集Unicode后的命令行设置字符集多字节后的命令行

    从上面可以看出,_UNICODE宏用于定义C/C++语言中的定义,比如定义C语言库函数的版本之类的,而UNICODE则是定义Windows函数的版本。其实这两者,是有一个约定的,在非Windows函数中,定义宏一般使用_表示非Windows宏定义。这样作为区分标志。这种约定是非常常见的,你可以到stdio.h头文件中去看看。当然这只是一个约定,你也可以不遵守,但是你看到标准的微软代码中,从中可以看出差别,有时候是很有帮助的。
    _UNICODE定义了_T宏,设置后,可以让此宏包含的字符串都是设定的字符集的字符。需要清楚的一点就是,在tchar.h中,并不会去定义_UNICODE宏,而只是去根据这个宏是否被定义,以确定项目使用的是什么字符集,从而使用对应版本的字符和函数。设置字符集在工程项目属性中设置。如果项目中设置的字符集是Unicode,那么_T代表的就是Unicode字符集,_txxx版本的函数代表的就是xxxW()的Unicode版本的函数。这样,不管项目的字符集如何改变,都不用更改代码。
如果此时,你没有设置宏UNICODE,那么在不使用Windows函数的情况下,没有任何问题。这都是自动正确匹配的。但是此时使用Windows的函数,如MessageBox函数,使用的则是根据宏UNICODE来判断得到的函数版本,如果定义了此宏,那么MessageBox就是Unicode版本,否则就是ANSII版本。
    在预处理器中可以加入此宏,表示设置Unicode字符集。如果你没有加入,那么在使用MessageBox函数时,使用的是ANSII版本,这样的话,字符是占一个字节。遇到一个空字符即表示字符串结束。在定义了_UNICODE情况下,_T可以正常使用,没有问题。然后使用MessageBox就会发现只能显示一个字符。因为存入内存的是Unicode字符,英文则表现为第二个字节为0,所以只能显示一个字符。如果是中文,那么在ANSII字符表中找不到对应的字符,就出现乱码。这也是为什么推荐使用设置字符集的原因。
    幸运的是,在VS中,项目属性里,设置字符集只需要更改使用的字符集即可同步设置这两个宏,就会保证,无论是C/C++环境里,还是Windows环境里,都能同时设置和取消,使用时也不会出问题。

    最后总结一下,项目判断使用的是什么字符集,利用_UNICODE 和 UNICODE 宏是否被定义来判断的。如果设置了,表示使用的是UNICODE字符集,否则是非UNICODE字符集。_UNICODE用于非Windows环境中的函数等定义,而 UNICODE用于Windows环境中的函数定义,这是个约定。而定义这两个宏,则在预处理器指令中。可以直接填,也可以使用选择字符集即可自动填上。