博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
isspace函数的debug版本处理中文程序异常
阅读量:3258 次
发布时间:2019-05-17

本文共 2296 字,大约阅读时间需要 7 分钟。

开发环境 :VS2008

示例代码:

#include 
#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; }

上述 代码(没有设置 
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 解决此问题
    
  

转载地址:http://iqckj.baihongyu.com/

你可能感兴趣的文章
Leecode 面试题 17.16. 按摩师
查看>>
Leecode 892. 三维形体的表面积
查看>>
Leecode 999. 车的可用捕获量
查看>>
Leecode 914.卡牌分组
查看>>
Leecode 面试题62. 圆圈中最后剩下的数字
查看>>
Leecode912. 排序数组
查看>>
Leecode 1111. 有效括号的嵌套深度
查看>>
Leecode 42. 接雨水
查看>>
云服务器上关于分布式文件系统FastDFS的安装教程以及个人遇到的所有排坑
查看>>
Leecoe 72. 编辑距离
查看>>
git命令回滚撤销自己的错误覆盖提交
查看>>
fastdfs连接超时报错解决方案
查看>>
Leecode202. 快乐数
查看>>
windows10解决80端口被占用的问题
查看>>
ElasticSearch快速入门之创建索引库、创建映射、创建文档、搜索文档
查看>>
用故事巧妙帮助理解公钥和私钥的区别和联系
查看>>
application.properties 文件和 application.yml 文件区别以及加载顺序
查看>>
阿里云服务器安装docker,拉取常用的mysql,redis,nginx等镜像
查看>>
链表之反转链表专题
查看>>
mybatis关于出现Parameter ‘XXX‘ not found. Available parameters are [collection, list]问题的解决方案
查看>>