首先知道一点,sizeof 用来计算数组时,是计算数组字节的,而不是数组的元素个数。这一点,在使用 sizeof 来计算通常的 char 类型数组时,所得到的值既表示数组的元素个数又表示数组的整个大小。但 sizeof 用来计算 Unicode 或者说是 wchar_t 这类型的数组时要小心,否则很可能造成缓冲区溢出。
比如,如果声明一个数组 TCHAR buffer[256]; 那么用 sizeof 来测量该数组是 512 ,而不是 256,尽管 buffer 数组中的元素为 wchar_t 类型且为 256 个。
_stprintf_s() 函数是 sprintf() 的通用类型,它的第 2 个函数在 MSDN 里表示 "Maximum number of characters to store." ,即要存储的字符数的最大个数。下面的这个程序里,我们可能会不小心如下使用 _stprintf_s() 和 sizeof() :
[C++] 纯文本查看 复制代码
#include "stdafx.h"
int _tmain(int argc, LPTSTR argv[])
{
TCHAR buf[100];
int len = _stprintf_s(buf, sizeof(buf), _T("%s"), _T("Hello World"));
printf("wote %d characters\n", len);
return 0;
}
程序初看上去没什么问题,但是如果是定义了 _UNICODE 后(此时 buf 里的元素类型是 wchar_t 而不是 char) 问题就来了。
上面程序运行后会崩溃,为什么会发生这种情况呢?我们不是只写了一个 "Hello World" 到 buf 中吗?而 buf 的空间又足以容纳这个字符串。此时,你可能会单步去调试,发现程序是在 return 0; 后发生了崩溃 -- 调试器还可能会好心的提示你发生了缓冲区溢出。
实际上,问题的关键在与 _stprintf_s() 中的第 2 个参数 sizeof(buf) ,它的值是 200,而不是 100 --- 这是程序崩溃的关键所在!在 _stprintf_s() 函数里,会有这么一道工序,在将 "Hello World" 填入 buf 之后,_stprintf_s() 还会调用 memset() 来清理一下 "Hello World" 后面的一段空间(这段空间的长度和 "Hello World" 的长度加起来刚好等于 400,即 200 个 wchar_t 类型长度)。如此一来,势必会冲毁 main() 函数的返回地址 --- 所以当程序执行过 return 0; 时因为找不到返回地址而发生崩溃。
因此,当我们使用如 _stprintf_s() 这种通用类型的函数时,要小心第 2 个参数的使用,特别是使用 sizeof() 直接来计算数组长度时!如果确定数组元素为 wchar_t 类型,那么 _stprintf_s() 函数的第 2 个参数应该这么写 sizeof(buf)/2 。一般情况下,最简单且安全的办法是,数组的元素个数用一个宏来表示,则 _stprintf_s() 的第 2 个参数就直接用该宏作为参数。 |