在编程中使用的字符和字符串形式归结于两种:ANSI和Unicode。由于Unicode字符字符串在国际上更通用,以及有利于COM和.NET Frameword进行互操作,更好的防范了缓冲区溢出的问题,所以编程中极力推荐使用Unicode字符和字符串。
ANSI中的字符和字符串为一个字节的char类型,而Unicode中的字符和字符串为两个字节的wchar_t内建数据类型。他们的常见使用方式为:
char c = 'A'; char szBuffer[100] = "A String";
wchar_t c = L'A'; wchar_t szBuffer[100] = L"A String";
在WinNT.h中,有大量方便的数据类型以供我们使用:
typedef char CHAR;
typedef wchar_t WCHAR;
typedef CHAR *PCHAR;
typedef CHAR *PSTR;
typedef CONST CHAR *PCSTR;
typedef WCHAR *PWCHAR;
typedef CONST WCHAR *PWCSTR;
为了在使用ANSI或Unicode字符/字符串时能够通过编译,WinNt.h中还有如下的宏:
#ifdef UNICODE
typedef WCHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
#define __TEXT(quote) L##quote
#else
typedef CHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST CHAR *PCTSTR;
#define __TEXT(quote) quote
#endif
#define TEXT(quote) __TEXT(quote)
使用上面的宏,无论使用ANSI还是Unicode字符都能通过编译。如:
TCHAR c = TEXT('A');
TCHAR szBuffer[100] = TEXT("A String");
当一个windows函数的参数列表中有字符串,则该函数通常有两个版本,一个是ANSI版本(即在函数名最后加一个A),一个是Unicode版本(即在函数名最后加一个W),如CreateWindowExW,CreateWindowExA。但也有一些例外情况,如windowsAPI的一些函数(WinExec和OpenFile)存在的目的就是为了向后兼容16位的windows程序,因为后者只支持ANSI字符串。在开发新程序的时候,应避免使用这些函数,调用新的函数(CreateProcess和CreateFile)来代替。随着Microsoft的发展,开始倾向于某些函数只有Unicode版本(ReadDirectoryChangesW 和 CreateProcessWithLogonW),Microsoft将COM从16位windows移植到Win32时,做出了一个重要决策,将所有需要字符串作为参数的COM接口方法都只接受Unicode字符串,因为COM一般用于不同的组件彼此间“对话”,Unicode是传递字符串的理想选择。
C运行库中的字符串函数和安全字符串函数(前面名字相同,后面加了一个_s):
_tcslen,测试字符串的长度
_tcscat,连接字符串
_tcscpy,复制字符串
所有的安全字符串函数的首要任务是验证传给它们的参数值,检查项目包括:指针不为NULL,整数在有效范围内,枚举值是有效的,缓冲区足以容纳结果数据。如果检查有一项失败,函数会设置线程的c运行时变量errno。然后返回一个errono_t值来指示成功或失败。然而函数并不实际返回(自己指定的函数除外),如果是调试版本,系统会弹出一个不友好的对话框,然后终止应用程序进行。如果是发行版本,则直接终止程序运行。
c运行时允许我们提供自己的函数,在它检测到参数无效时,就会调用我们的函数。在这个函数中我们可以记录失败信息并提示,附上一个调试器或做其他事情。要启用此功能:
首先要定义好一个函数: void InvalidParameterHandler(PCTSTR expression, PCTSTR function, PCTSTR file, unsigned int line, uintptr_t /*pReserved*/);
expression描述c运行时实现代码中可能出现的函数调用失败的原因,但是它的显示方式并不友好。
function描述出错的函数名
file描述出错的源代码文件
line描述出错的源代码行号
其次调用_set_invalid_parameter_handler来注册这个处理程序。
最后要在应用程序开头的地方调用_CrtSetReportMode(_CRT_ASSERT, 0);
从而禁止可能由C运行时触发的所有调试中断对话框。
字符串的更多控制(可截断或填充):
StringCchCat、StringCchCatEx,连接字符串
StringCchCopy、StringCchCopyEx 复制字符串
StringCchPrintf、StringCchPrintfEx 按指定格式填充字符串
CompareString、CompareStringEx比较一般字符串
CompareStringOrdinal 比较程序内部所用的字符串(如路径名,注册表项/值,XML元素/属性等)使用码位比较,不考虑区域设置,只支持Unicode字符串
sizeof 与 _countof的区别:
sizeof 查询目标所占的字节数
_countof查询目标的元素个数
字符串转换:
WideCharToMultiByte,将Unicode字符串转换为ANSI字符串
MultiByteToWideChar,将ANSI字符串转换为Unicode字符串
转换步骤:
先调用一次转换函数来获取转换所需要的空间大小
然后构建空间
最后再调用转换函数转换字符串
释放内存
检测文件的字符串版本:
BOOL IsTextUnicode(CONST PVOID pvBuffer, int cb, PINT pResult);
pvBuffer要测试的缓冲区地址
cb指定pvBuffer缓冲区的字节数
pResult指定希望函数进行哪些测试,为NULL表示执行每一项测试