如何表示字符串中跨平台 (Windows、 iOS、 Android) c + + 应用程序吗?

发布时间: 2014/3/3 18:59:14
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我正在开发的核心代码库将是跨平台的应用程序窗口、 iOS 和 android 系统。

我的问题是: 如何应国内代表字符串被此应用程序所使用,以便能够有效地利用它们在所有三个平台上?

它是重要的是要注意,我使用 DirectWrite 沉重在 Windows 中,其中的 API 函数通常期望 wchar_t * 要传递 (btw.API 文档状态"到一个数组中的指针",我不知道这是否意味着他们在 utf-16 编码或不) Unicode 字符。

我看到三个不同的方法 (但是我发现它很难把握所以也许错过了一些重要的概念以跨平台的方式处理与 c + + 的 Unicode 字符串的详细信息):

  • 国内到处使用 std::string (并将这些字符串存储在 utf-8 编码?),并将它们转换为 wchar_t * 它为 DirectWrite API (我不知道什么所需的文本处理的 Api Android 和 iOS 的尚未) 需要。
  • 国内到处使用 std::wstring。如果我理解的事情的权利,因为 wchar_t 是 iOS 和 Android 上的 4 个字节 (这意味着会将字符串存储在 Windows 中,关于 utf-16 和 UTF-32 在 Android/iOS?),这不是有效内存使用角度来看,从
  • 创建字符串的抽象与抽象基类,并执行内部存储专门为不同的平台。

最好的解决办法是什么?和顺便说一句,有没有任何现有的跨平台库那抽象字符串处理吗?(另外,和读的 Unicode 字符串序列化)

(更新: 删除了部分和关于 char * 与 std::string 的区别的问题.)

解决方法 1:

我的问题的一部分来自我误会了,或不完全理解的字符串wstring类在 c + + 中如何工作 (我来自 C# 背景)。这个很好的答案说明了两个和优缺点的差异: std::wstring VS std::string

如何的字符串和 wstring 工程

对我来说,有关字符串和 wstring 类的单一最重要发现是在语义上他们并不代表编码的文本,而是简单地"字符串"的 char 或 wchar_t 的一块。他们是更像是一个简单的数据数组与某些特定字符串操作 (像追加和 substr) 而不是表示文本。他们都意识到任何种类的字符串编码无论怎样,单独作为一个单独的字符处理 char 或 wchar_t 的每个元素。

编码

然而,在大多数系统上,如果您创建一个字符串从一个像这样的特殊字符的字符串文本:

std::string s("ű");

Ű字符将由多个字节在内存中,但这与 std::string 类无关,这是编译器的一个功能,它可以进行编码以 UTF8 字符串文本 (不是每个编译器虽然)。(和以 L 为前缀的字符串文本将由 UTF16 或 UTF32 或别的方法,具体取决于编译器的 wchar_t-s 表示)。
因此将在内存中与两个字节表示字符串"ű" : 0xC5 0xB1和 std::string 类不会知道那些两个字节在语义上的意思是一个字符 (一个 Unicode 代码点) 在 UTF8,因此示例代码:

std::string s("ű");
std::cout << s.length() << std::endl;
std::cout << s.substr(0, 1);

会产生以下结果 (根据编译器,某些编译器不做字符串文字作为 UTF8,和某些编译器取决于源文件的编码):

2
�

Size() 函数返回 2,因为 std::string 知道的唯一的一件事是它存储两个字节 (两个字符为单位)。"原始地"以及 substr 工程,它将返回一个字符串,包含单个 char 0xC5,显示为,因为它不是一个有效的 UTF8 字符 (但这并不在意 std::string)。

从那我们可以看到,世卫组织处理的编码是各种文本处理 Api 的平台,像简单coutDirectWrite

我的方法

在我的应用程序中 DirectWrite 是非常重要的它只接受字符串编码的 UTF16 (以 wchar_t * 指针的形式)。所以我决定将这些字符串存储在内存中并以 UTF16 编码的文件中。不过,我想要一个跨平台实现它可以处理 Windows、 Android 和 iOS,是不可能的std::wstring,因为其数据的大小 (和它适合使用的编码) 是依赖于平台上的 UTF16 字符串。

若要创建一个跨平台,严格 UTF16 字符串类模板化basic_string是 2 个字节长的数据类型。非常令人惊讶-至少我-我几乎没有任何有关这一信息网上找到,我将我的解决方案基于种方法。下面是代码:

// Define this on every platform to be 16 bytes!
typedef unsigned short char16;

struct char16_traits
{
    typedef char16 _E;
    typedef _E char_type;
    typedef int int_type;
    typedef std::streampos pos_type;
    typedef std::streamoff off_type;
    typedef std::mbstate_t state_type;
    static void assign(_E& _X, const _E& _Y)
    {_X = _Y; }
    static bool eq(const _E& _X, const _E& _Y)
    {return (_X == _Y); }
    static bool lt(const _E& _X, const _E& _Y)
    {return (_X < _Y); }
    static int compare(const _E *_U, const _E *_V, size_t _N)
    {return (memcmp(_U, _V, _N * 2)); }
    static size_t length(const _E *_U)
    {
        size_t count = 0;
        while(_U[count] != 0)
        {
            count++;
        }
        return count;
    }
    static _E * copy(_E *_U, const _E *_V, size_t _N)
    {return ((_E *)memcpy(_U, _V, _N * 2)); }
    static const _E * find(const _E *_U, size_t _N, const _E& _C)
    {
        for(int i = 0; i < _N; ++i) {
            if(_U[i] == _C) {
                return &_U[i];
            }
        }
        return 0;
    }
    static _E * move(_E *_U, const _E *_V, size_t _N)
    {return ((_E *)memmove(_U, _V, _N * 2)); }
    static _E * assign(_E *_U, size_t _N, const _E& _C)
    {
        for(size_t i = 0; i < _N; ++i) {
            assign(_U[i], _C);
        }
        return _U;
    }
    static _E to_char_type(const int_type& _C)
    {return ((_E)_C); }
    static int_type to_int_type(const _E& _C)
    {return ((int_type)(_C)); }
    static bool eq_int_type(const int_type& _X, const int_type& _Y)
    {return (_X == _Y); }
    static int_type eof()
    {return (EOF); }
    static int_type not_eof(const int_type& _C)
    {return (_C != eof() ? _C : !eof()); }
};

typedef std::basic_string<unsigned short, char16_traits> utf16string;

与上面的类中,存储在字符串和UTF16 的原始数据被传递到各种不同的平台,所有的目前在似乎支持 UTF16 编码的特定 API 函数。
执行情况可能不是完美的然而的追加、 substr 和大小的职能似乎正常工作。我仍然没有多少经验的字符串处理 c + + 中随意注释编辑如果我说出了不正确。

官方微信
官方QQ群
31647020