示例代碼:
#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <functional>
#include <locale>
#include <cctype>
using namespace std;
inline string& ltrim(string &str) {
string::iterator p = find_if(str.begin(), str.end(), std::not1(ptr_fun<int, int>(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<int , int>(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 解決此問題
---------------------
作者:Mr_John_Liang
來源:CSDN
原文:https://blog.csdn.net/liangzhao_jay/article/details/78064399
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!