一、
Unicode标准:
每个Unicode字符都是使用UTF-16编码,UTF-16将每个字符编码为2个字节,UTF-16在节省空间和简化编码之间提供了一个良好的折衷。
ANSI标准:
使用UTF-8编码,一个字符使用一个字节,占8位。c语言的char类型用来表示一个8位的ANSI字符。
二、
WIndows系统与Unicode标准:
自Windows NT起,Windows所有版本都采用Unicode标准,所有核心函数都采用Unicode字符串,如果调用一个函数传入的参数是ANSI字符串,那么函数会先将其转换冲Unicode字符串,再传给操作系统,如果希望函数返回ANSI字符串,那么操作系统会先将Unicode字符串转换成ANSI字符串,这些转换都在幕后进行的,因此系统会产生时间和内存上的消耗。
三、
Microsoft的C/C++编译器与Unicode字符:
现在Microsoft的C/C++编译器定义了一个内建的数据类型wchar_t,它表示一个16位的Unicode(UTF-16)字符,在默认情况下,VS建立一个新项目时,是使用Unicode标准字符的。
声明Unicode字符或字符串的方法:wchar_t c = L'A'; 在前面加个L表示通知编译器该字符(串)应当编译为Unicode字符。输出要用std::wcout。
四、
源代码如何保持一致性:
windows开发团队与c语言稍有区别,他们在Windows头文件WinNT.h中定义了以下数据类型:
typedef char CHAR ;
typedef wchar_t WCHAR;
//指针
typedef CHAR *PCHAR;
typedef CHAR *PSTR;
typedef CONST CHAR *PCSTR;
typedef WCHAR PWCHAR;
typedef WCHAR PWSTR;
typedef CONST WCHAR *PCWSTR;
在源代码中,具体使用哪种字符类型不重要,重要的是保持一致性,增加代码的可维护性, WinNT.h中定义了以下类型和宏:
#ifdef UNICODE
typedef WCHAR TCHAR ,*PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
#else
typedef WCHAR TCHAR ,*PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
所以无论采用哪种字符标准,使用TCHAR都是编译通过 TCHAR szBuffer[100] = _T("hello world!"); 故TCHAR称为通用类型。
此外对一些API函数也做了一些保持一致性的修改,如下:
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif
五、
C运行库中的Unicode函数和ANSI函数:
对于计算字符串长度的函数,C运行库中,strlen是返回ANSI字符串的长度,与之对于的是wcslen,返回的是Unicode字符串的长度。
在TChar.h文件中,定义了以下宏:
#ifdef UNICODE
#define _tcslen wcslen
#else
#define _tcslen strlen
#endif
所以在代码中不用管是否采用Unicode标准,可以直接调用_tcslen函数。
但是,任何修改字符串的函数都存在一个安全隐患,如果目标字符串的缓冲区不够大,无法容下所生成的字符串,将会导致内存中的数据被破坏,例如strcpy和wcscpy,所以最好是用wcscat这样指定缓冲区长度的字符串处理函数。相反的,像stlen和wcslen等不会修改传入字符串的函数则是安全的。
目前微软提供了一些新版本的字符串安全处理函数(tchar.h文件里),即在函数名后面加_s ,例如_tcscpy_s,_tcscat_s,memcpy_s,memmove_s。它们的首要任务就是验证传给它们的参数值。例如指针不为NULL,整数在有范围内,缓冲区是否能容纳结果大小等。
这里我介绍一个宏_countof, 一些函数通常需要我传入某个参数的缓冲区的字符数,而非字节数,所以我们就应该传入_countof(szBuffer)而不是sizeof(szBuffer) 。在手动分配一块内存的时候,要记住内存是以字节累分配的,这意味着我们必须调用malloc(nChars * sizeof(TCHAR))。
VC中有一个计算数组元素个数的MACRO
代码如下:
#if !defined(_countof)#if !defined(__cplusplus)#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))#elseextern "C++"{template <typename _CountofType, size_t _SizeOfArray>char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];#define _countof(_Array) sizeof(*__countof_helper(_Array))}#endif#endif
C++版本的实现充分地利用了函数模板的参数自动推导机制,但我始终没聊到函数指针也可以模板化,
六、宽字符与窄字符转换
size_t mbstowcs(wchar_t *wcstr, const char *mbstr, size_t count)//由一个窄字符转换到一个宽字符
size_t wcstombs(char *mbstr, const wchar_t *wcstr, size_t count)//由一个宽字符转换到一个窄字符