将内存中的16位转换为std :: string

时间:2013-07-29 18:29:16

标签: c++ string unicode stdstring wchar

我从内存中的结构中得到16位,我需要将它们转换为字符串。 16位代表一个unicode char:

typedef struct my_struct {
    unsigned    unicode     : 16;
} my_struct;

我开始将这些位转换为一个unsigned char,它的值足够小,可以放入一个char中。但是,对于像'♪'这样的字符,它会截断不正确。这就是我到目前为止所做的:

        char buffer[2] = { 0 };
        wchar_t wc[1] = { 0 };

        wc[0] = page->text[index].unicode;
        std::cout << wc[0] << std::endl; //PRINT LINE 1
        int ret = wcstombs(buffer, wc, sizeof(buffer));
        if(ret < 0)
            printf("SOMETHING WENT WRONG \n");
        std::string my_string(buffer);
        printf("%s \n", my_string.c_str()); //PRINT LINE 2

当前打印行1打印:“9834”,打印行2打印:“”(空字符串)。我想让my_string包含'♪'。

3 个答案:

答案 0 :(得分:2)

如果我已正确完成转换,则UTF-16中的0x9834(16位 Unicode)转换为三字节序列0xE9,0xA0, 0xF4,UTF-8(8位Unicode)。我不知道其他的狭窄 字节编码,但我怀疑任何短于2个字节。 您将两个字节的缓冲区传递给wcstombs,这意味着 返回的字符串,最多1个字节。 wcstombs停止了 翻译(没有失败!),当没有更多的空间 目标缓冲区。您也未能L'\0'终止 输入缓冲区。这不是问题,因为 wcstombs会在它到达之前停止翻译,但是你 通常应该添加额外的L'\0'

那该怎么做:

首先,和formost,在调试这类事情时,请看一下 wcstombs的返回值。我敢打赌它是0,因为 缺乏空间。

其次,我会给自己一点保证金。合法的Unicode 在UTF-8中最多可以产生四个字节,因此我将分配给 输出至少5个字节(不要忘记尾随'\0')。 同样,您需要输入尾随L'\0'。 所以:

char buffer[ 5 ];
wchar_t wc[] = { page->text[index].unicode, L'\0' };
int ret = wcstombs( buffer, wc, sizeof( buffer ) );
if ( ret < 1 ) {    //  And *not* 0
    std::cerr << "OOPS\n";
}
std::string str( buffer, buffer + ret );
std::cout << str << '\n';

当然,毕竟还有什么问题 (最终)显示设备使用UTF-8(或任何 多字节窄字符编码是--- UTF-8差不多 在Unix下通用,但我不确定Windows。)但是 因为你说显示"\u9834"似乎有效,所以 应该没事。

答案 1 :(得分:1)

请仔细阅读“字符编码”的含义,例如:What is character encoding and why should I bother with it

然后找出你要进入的编码,以及你需要在输出上使用的编码。这意味着要弄清楚你的文件格式/ GUI库/控制台的期望。

然后使用像libiconv这样可靠的东西在它们之间进行转换,而不是如此实现定义的那几乎无用的wcstombs()+ wchar_t。

例如,您可能会发现您的输入是UCS-2,您需要将其输出为UTF-8。我的系统有32位wchar_t,我不会指望它从UCS-2转换为UTF-8。

答案 2 :(得分:1)

要将UTF-16转换为UTF-8,请使用codecvt_utf8<char16_t>

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

int main() {
    char16_t wstr16[2] = {0x266A, 0};
    auto conv = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{};
    auto u8str = std::string{conv.to_bytes(wstr16)};
    std::cout << u8str << '\n';
}