wstring.size()在xcode或visual c++中的工作方式不同

wstring.size() works differently in xcode or visual c++

本文关键字:c++ 工作 方式不 visual size xcode wstring      更新时间:2023-10-16

我运行了相同的代码,用于确定宽字符串中的字符数。测试字符串包含ascii、数字和朝鲜语。

#include <iostream>
using namespace std;
template <class T,class trait>
void DumpCharacters(T& a)
{
    size_t length = a.size();
    for(size_t i=0;i<length;i++)
    {
        trait n = a[i];
        cout<<i<<" => "<<n<<endl;
    }
    cout<<endl;
}
int main(int argc, char* argv[])
{
    wstring u = L"123abc가1나1다";
    wcout<<u<<endl;
    DumpCharacters<wstring,wchar_t>(u);
    string s = "123abc가1나1다";
    cout<<s<<endl;
    DumpCharacters<string,char>(s);
    return 0;
}

显而易见的是,Visual C++2010中的wstring.size()返回字母数(11个字符),而不管它是ascii还是国际字符。然而,它在Mac OS X中的XCode 4.2中返回字符串数据的字节计数(17字节)。

请回复我如何获得宽字符串的字符长度,而不是xcode中的字节数。

---2月12日添加--

我发现wcslen()在xcode中也返回17。它在vc++中返回11。这是经过测试的代码:

const wchar_t *p = L"123abc가1나1다";
size_t plen = wcslen(p);

---2月18日添加--

我发现llvm 3.0导致了错误的长度。将编译器前端从llvm3.0更改为4.2 后,此问题得到了修复

wcslen()在Xcode中的工作方式不同,VC++说明了细节。

如果std::wstring版本使用17个字符,这是一个错误:它应该只使用11个字符。使用gcc和clang的最新SVN头,它为std::wstring使用11个字符,为std::string使用17个字符。我认为这是意料之中的事。

请注意,标准C++库内部对"字符"的概念与使用多字编码时的预期不同(例如,UTF-8用于char类型的字,UTF-16用于16位的字)。这是描述字符串的章节的第一段(21.1[strings.general]):

本条款描述了用于操作任何非数组POD(3.9)类型的序列的组件。在这个子句中,这种类型被称为类字符类型,类字符类型的对象被称为类似字符的对象或简单的字符。

这基本上意味着,当使用Unicode时,的各种函数不会关注代码点的组成,而是将字符串作为单词序列进行处理。这是严重的影响,例如在生成子字符串时会发生什么,因为这些子字符串可能很容易将多字节字符分开。目前,标准C++库不支持在内部处理多字节编码,因为它假设从编码到字符的转换是在读取数据时完成的(相应地,在写入数据时则是另一种方式)。如果您在内部处理多字节编码的字符串,则需要注意这一点,因为根本不支持。

人们认识到,这种状况实际上是一个问题。对于C++2011,添加了字符类型char32_t,它应该比wchar_t更好地支持Unicode字符(因为Unicode使用20位,而wchar_t只允许支持16位,这是在Unicode承诺最多使用16位的时候在一些平台上做出的选择)。然而,这仍然不能处理组合字符的问题。C++委员会承认这是一个问题,在标准C++库中进行适当的字符处理是件好事,但到目前为止,还没有人提出解决这个问题的全面建议(如果你觉得你想提出这样的建议,但你不知道怎么做,请随时联系我,我会帮助你提交建议)。

XCode 4.2在初始化string s时,显然使用UTF-8(或类似的东西)作为窄多字节编码来表示程序源代码中的字符串文字"123abc가1나1다"。该字符串的UTF-8表示恰好有17个字节长。

宽字符表示(存储在u中)是11个宽字符。有许多方法可以将窄编码转换为宽编码。试试这个:

#include <iostream>
#include <clocale>
#include <cstdlib>
int main()
{
    std::wstring u = L"123abc가1나1다";
    std::cout << "Wide string containts " << u.size() << " charactersn";
    std::string s = "123abc가1나1다";
    std::cout << "Narrow string contains " << s.size() << " bytesn";
    std::setlocale(LC_ALL, "");
    std::cout << "Which can be converted to "
              << std::mbstowcs(NULL, s.c_str(), s.size())
              << " wide characters in the current locale,n";
}

使用.length()而不是.size()来获取字符串长度。

std::string和std::wstring是在char和wchar_t上模板化的std::basic_string的typedef。size()成员函数返回字符串中元素的数量-char或wchar_t的数量。"和L"不涉及编码。