CRT中windows部分中,已经废弃了_tcsXXX之类的函数,如果你想使用的话,vs会提醒使用安全_tcsXXX_s之类的安全函数。
#include<iostream>
#include<tchar.h>
int main() {
TCHAR szBefore[] = _T("AAAAA");
TCHAR szBuffer[10] = _T("---------");
TCHAR szAfter[] = _T("BBBBB");
_tcscpy(szBuffer, _T("0123456789"));
return 0;
}
解决方法写的很清楚了。接着我们来看看最新的安全函数
#include<iostream>
#include<tchar.h>
int main() {
TCHAR szBefore[] = _T("AAAAA");
TCHAR szBuffer[10] = _T("---------");
TCHAR szAfter[] = _T("BBBBB");
_tcscpy_s(szBuffer,_countof(szBuffer) ,_T("0123456789"));
return 0;
}
产生了一个Assertion。原因是szBuffer是10个。而“0123456789”这个字符串是11个的(加一个‘\0’)。所以造成了内存的移除。而_tcscpy_s函数检查到了这一点,所以做了相应提示。
如果再Debug模式下会出现对上面话框。但是再发行版的情况下程序就会直接奔溃了。所以这是一个严重的问题 ,我们要找到其中原因并解决。windows 给我们提供了很多调试工具来查找错误(内存窗口,监视窗口,堆栈调用)。当然也提供了一些编程手段
现在我们来看一下下面这个程序
#include<iostream>
#include<Windows.h>
#include<tchar.h>
//安全函数在出现断言时除了停止程序程序出现对话框以外还能制定一个处理函数。详细参数可以自行参考 msdn
void InvalidParameterHanlder(
wchar_t const*,
wchar_t const*,
wchar_t const*,
unsigned int,
uintptr_t
);
int main(void)
{
// crt函数(crtdbg.h 被iostream包括),下面设置会禁用所有有c运行时川信啊的Assetion 错误。当让你也可以在异常设置窗口中设置
_CrtSetReportMode(_CRT_ASSERT,0);
//绑定断言处理函数
_set_invalid_parameter_handler(InvalidParameterHanlder);
TCHAR szBefore[5] = _T("BBBB");
TCHAR szBuffer[10]=_T("---------");
TCHAR szAfter[5] = _T("AAAA");
_tcscpy_s(szBuffer,_countof(szBuffer),_T("0123456789"));
//erro 是一个宏,他会调用_errno(),这个方法和GetLastError一样返回安全函数堆栈的错错误码(errno.h中定义,被iostream包括)
if (errno == STRUNCATE) {
std::cout << "result: STRUNCATE" << std::endl;
}
if (errno == ERANGE) {
std::cout << "result: ERANGE" << std::endl;
}
if (errno ==S_OK) {
std::cout << "result: S_OK" << std:: endl;
}
system("pause");
return 0;
}
void InvalidParameterHanlder(
wchar_t const* a,
wchar_t const* b,
wchar_t const* c,
unsigned int d,
uintptr_t e
) {
//有一点特别注意,这些参数值只有在定义了DEBUG时才会有值,不然全是NULL,所以在发行版的程序下面代码会让程序奔溃的
std::wcout << a <<"\n"<< b <<"\n"<< "\n" <<c<<std::endl;
}
上面程序刚好说明了一个问题。如果我们强制让上面代码运行让返回结果变成ERANGE。
我们在_tcscpy_s函数和system函数分别打上断点
遇到_tcscpy_s断点
遇到system断点
所以当拷贝的字符串大于缓冲区的大小时。就会返回ERANGE(error range)。在内存中的表现就是字符串被阶段成一个空字符串。一个\0,后面全被0xfe填充
TIps:
上面的0XCC是什么呢。这是一个标记。如果你对编译器设置了运行时检查(/RTCs,/RTCu或/RTC1)那么编译器会把变量后的的剩余空间用这个符号填充。从而检查缓冲区的溢出。所以这个编译选项是要开启的