本文共 2296 字,大约阅读时间需要 7 分钟。
开发环境 :VS2008
示例代码:
#include上述 代码(没有设置 setlocale 的时候 )在debug编译的情况下会 assert失败。没有办法,只好跟踪到c运行库里,isspace的实现如下(在"_ctype.c"文件里): extern __inline int (__cdecl isspace) ( int c ) { if (__locale_changed == 0) { return __fast_ch_check(c, _SPACE); } else { return (_isspace_l)(c, NULL); } } 跟踪发现,__locale_changed的值为0,走第一个分支,调用__fast_ch_check,它其实是个宏定义,最后进入_chvalidator函数,它的实现代码如下: extern "C" int __cdecl _chvalidator( int c, int mask ) { _ASSERTE((unsigned)(c + 1) <= 256); return _chvalidator_l(NULL, c, mask); } 错误就发生在这个函数的第一行“ _ASSERTE((unsigned)(c + 1) <= 256);”。 代码看到这里,错误的原因基本也就出来了。“高”的GBK编码是“b8 df”,调用isspace函数是逐个字节判断,但是isspace和_chvalidator接受的参数都是int,这样就会产生一个char到int的转型,在vc下,char默认是"signed char",这样char“b8”转型到int后,会变成一个负数,然后在assert的时候,又强制转型为unsigned,它又变成了一个非常巨大的正数,自然assert就失败了。 为什么在gcc下没有错误?gcc下的isspace函数实现我倒没看,不过我的gcc中的char默认就是“unsighed char”,所以即使isspace的实现跟上面的一样,也不会产生问题。 另:在win32 release和wince下,也不会有上述问题,因为这几种环境下isspace的实现跟上面不一样。 问题找到了,剩下的就看怎么解决了。 首先用用一个最简单的方法,既然问题发生在转型上,只要把char的默认类型改为unsigned char就可以了,vc也提供了这个选项。但这有几个问题,一是别人用我的代码的时候还得修改编译选项,二是修改了整个工程的编译选项可能会对其它代码产生不好的影响。 既然上面的方法不大好操作,那就再想想别的方法。经观察发现,isspace函数中靠__locale_changed变量控制流程走向,搜索整个crt的源代码,发现__locale_changed的值只有在setlocale函数中发生了改变。最后,我把代码进行修改 添加了 setlocale 解决此问题#include #include #include #include #include #include using namespace std;inline string& ltrim(string &str) { string::iterator p = find_if(str.begin(), str.end(), std::not1(ptr_fun (isspace))); str.erase(str.begin(), p); return str; } inline string& rtrim(string &str) { string::reverse_iterator p = find_if(str.rbegin(), str.rend(), std::not1(ptr_fun (isspace))); str.erase(p.base(), str.end()); return str; } inline string& trim(string &str) { ltrim(rtrim(str)); return str; } int main(){ #if _DEBUG setlocale(LC_ALL, "chs"); #endif string str = "\t\r\n 123sggdery中 国455 68 \r\n"; string str1 = str; string str2 = str; cout << "str: ~" << str << "~" << endl << endl; cout << "ltrim(str): ~" << ltrim(str1) << "~" << endl; cout << "rtrim(ltrim(str)): ~" << rtrim(str1) << "~" << endl << endl; cout << "rtrim(str): ~" << rtrim(str2) << "~" << endl; cout << "ltrim(rtrim(str)): ~" << ltrim(str2) << "~" << endl << endl; cout << "trim(str): ~" << trim(str) << "~" << endl; return 0; }
转载地址:http://iqckj.baihongyu.com/