【问题标题】:wstring.size() works differently in xcode or visual c++wstring.size() 在 xcode 或 Visual c++ 中的工作方式不同
【发布时间】:2012-02-11 16:41:34
【问题描述】:

我运行了相同的代码来确定宽字符串中的字符数。测试的字符串有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() works differently in Xcode and VC++ 说细节。

【问题讨论】:

  • size()std::string 的情况下给出以字节为单位的大小(chars),在std::wstring 的情况下给出wchar_t 的大小。两者都不会给你字符串中的数字字符。
  • 你的“明显的事情”是错误的。

标签: c++ wstring


【解决方案1】:

std::wstring 版本使用 17 个字符是错误的:它应该只使用 11 个字符。使用 gcc 和 clang 的最新 SVN 头,它使用 11 个字符作为 std::wstring 和 17 个字符作为 std::string。我认为这是预期的结果。

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

本条款描述了用于操作任何非数组 POD (3.9) 类型的序列的组件。在本条款中,此类类型称为 char-like types ,而 char-like 类型的对象称为 char-like objects 或简称为 characters。

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

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

【讨论】:

  • 这不是错误;见 Cubbi 的回答。当我们的意思是 char/wchar_t 时,我们不要说“字符”:这种不精确正是 OP 还没有深入了解这个话题的原因。
  • 首先,我认为 Cubbi 还说 std::wstring 的大小必须是 11 而不是 17,即如果 @ 的大小 错误987654331@ 不是 11。此外,该标准考虑了存储在 std::stringstd::wstring 中的单位,即分别为 charwchar_t,“字符”:参见 21.1 [strings.general] 第 1 段: “在本条款中,此类类型称为 char-like 类型,而 char-like 类型的对象称为 char-like objects 或简称为字符。”我意识到在字符串中存储多字节编码对“字符”是什么有不同的理解。
  • 没错,因为这是我们正在讨论的主题(标准故意没有概念的主题),所以选择清楚地处理“字符”的更抽象含义是有意义的。此外,标准是否指定 [wide] 字符串文字的编码?我不认为是这样,在这种情况下,std::wstring 可以是它喜欢的任何东西;很高兴在那里被证明是错误的。
【解决方案2】:

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() << " characters\n";

    std::string s = "123abc가1나1다";
    std::cout << "Narrow string contains " << s.size() << " bytes\n";

    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";
}

【讨论】:

  • 对于std::string,您将获得std::stringchars 的计数,而不是字符数:std::string 中的chars 被滥用为字节如果它包含需要多个字节进行编码的字符。所有标准 C++ 字符处理都假定在内部,字符仅由一个 word 表示(char 表示 std::stringwchar_t 表示 std::wstring 等)。然而,问题是关于std::wstring,它应该能够每个只用一个词来表示韩语字符。
  • @DietmarKühl 我什至没有意识到 OP 声称 wstring::size() 返回 17。这将是一个编译器错误(wchar_t 足以表示任何字符),除非 OP 的系统很宽字符编码是深奥的东西。我不同意你的All of the standard C++ character processing assumes that internally a characters is represented by exactly one——很多 C++ 是根据多字节字符序列定义的。
【解决方案3】:

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

【讨论】:

  • 它们都返回相同的值。
【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-29
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-08
    • 2014-08-01
    • 1970-01-01
    相关资源
    最近更新 更多