如下操作实在类中定义的:
TCHAR m_illegal_chars[13];
TCHAR temp[13] = {_T('|'),
_T('*'),
_T('\\'),
_T(':'),
_T(';'),
_T('>'),
_T('<'),
_T('?'),
_T('"'),
_T(','),
_T('='),
_T('`') };
int i = sizeof(temp)/sizeof(temp[0]); 此时i= 13
_tcscpy_s(m_illegal_chars, i,temp);
上面没有问题。
但下面的代码
_tcscpy_s(m_illegal_chars,12,temp); 用12替换i
程序出现异常,down掉了,而且查看了m_illegal_chars为 0*\:;>",=` 而不是|*\:;>",=` 第一个字符没有拷贝成功;
解释:
类里面用_tcscpy_s要注意的小细节
复制字符串总是在后2到3个字节后开始,前几个字节不变,刚开始以为是UTF8头(EF BB BF)的问题,但那几个字节不是,文件也不是UTF8的,单步步进一看,errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR*_SRC)
这个函数的 _DEST还真的往前移了几个字节,ALT+8看汇编,才发现这个地址是this+偏移过来的,但偏移是4字节对齐,这个偏移前面有个bool型变量,导致偏移差了3个字节,vs2010自己还是4字节对齐,导致多加了3个。
字节对齐在结构体或类中。
影响字节对齐有几个因素。
1) 编译器对齐字节值。 一般默认为4,可以通过#pragra 更改
2) 类成员对齐字节值。 成员所占的字节
3) 类自己的对齐字节值。 类里面的最大成员的对齐值。 它将决定类在补齐字节时的值。
4) 类成员有效对齐值。 类成员对齐字节值和编译器对齐字节值中小的哪个。 它决定类成员占多大字节。
你应该看到了Assert窗口了
"Buffer is too small"
那原因是什么呢? 字符串str中有8个字符,加上字符串结束符'\0',应该要大小为9的buffer,这里才会出错,
至于要求使用strcpy_s,就是考虑到strcpy_s这一系列的函数,可以保证不做越界操作。
非常重要的一个问题:
win32平台上字符串的常见处理方式
1:强烈推荐使用UNICODE来编写程序。
1,使用unicode,可以使用一个exe,或者DLL来支持多国语言,方便实现本地化。
2,使用Unicode,可以节省WIN32API调用的时间和空间开销,下面会详细介绍。
3,可以更好地和COM组件交互,因为COM组件只支持UNICODE。
4,可以更好地和NETFRAMEWORK交互。
对于win32 API函数来说,目前的windows操作系统内部都使用UNICODE来实现和字符串有关的函数。但是通常,都提供ASCLL和Unicode两个版本的,如CreateWindowA,CreateWindowW,其实内部只有后者的真正实现,前者则是分配内存,转换传入的ASCLL字串为宽字符,然后传入后者,等待后者返回后,释放内存,并返回。在头文件中呢,微软定义了宏
#ifdef UNICODE
#define CreateWindow CreateWindowW
#else
#define CreateWindow CreateWindowA
#endif
,正是通过是否定义了UNICODE来决定调用哪一个。
那么,C标准库呢?C标准库中的字符串处理函数,则不像win32 API一样,只有宽字符版本的实现,C标准库有两个实现,一个实现是ANSI的,一个是UNICODE的,程序员可以在编译的时候来指定。这一点可以参看深入浅出MFC第一章。比如strlen是针对ASCLL的,wcslen是针对UNICODE的,标准库如何判断到底使用哪一个呢?标准库定义了宏:
#ifdef _UNICODE
#define _tcslen wcslen
#else
#define _tcslen strlen
#endif
可以看出来,标准库会将UNICODE的标识定义为包含下划线的形式,而微软的开发团队没有那样做,微软的是不带下划线的。不过,我们的程序一般来说,既要用到API,又要用到标准库函数,所以就有了一条规则,要么UNICODE和_UNICODE都指定,否则都不指定。
下面来总结一下一些原则吧:)
1,建议使用UNICODE。
2,建议不要使用char, wchar_t,而使用CHAR,WCHAR,最好包含tchar.h,使用TCHAR
3,计算字符数组长度时,使用sizeof(ArrayName)/sizeof(ArrayName[0])来计算。
4,同时定义UNICODE和_UNICODE,或者两个都不要定义。
5,使用windows API函数MultiByteToWideChar和WideCharToMultiByte函数来实现ACSLL字符和UNICODE字符的相互转换。
6,也可以使用C标准库中的wcstombs来执行转换。
经验教训:
一定注意在字符串操作时的越界问题,strcpy拷贝导致的越界没有提示, 会导致程序出现不可预测的bug(比如说以前执行正确函数 突然出现内存读取违法错误 崩溃了 头大,why, 可能和某地方的字符数组越界有关。),使用支持安全的strcpy_s(http://blog.csdn.net/shutear/article/details/8256096)