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

Convert 16 bits in memory into std::string

本文关键字:std 转换 string 内存      更新时间:2023-10-16

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

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

我首先将这些位转换为一个无符号的字符,该字符适用于足够小的值以容纳一个字符。但是,对于像"♪这样的字符,它会错误地截断。这是我到目前为止所拥有的:

        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包含"♪"。

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

那怎么办:

首先,在调试这种事情时,看看wcstombs 的返回值。 我敢打赌它0,因为空间不足。

其次,我会给自己一点余地。 法律统一码最多可以产生四个字节的 UTF-8,所以我会分配输出至少 5 个字节(不要忘记尾随''(。同样,您需要输入的尾随L''。所以:

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

当然,毕竟,仍然存在什么问题(最终(显示设备使用 UTF-8(或任何多字节窄字符编码是---UTF-8几乎Unix下的通用,但我不确定Windows。 但既然你说显示"u9834"似乎有效,它应该没问题。

请阅读一些关于"字符编码"的含义,如下所示: 什么是字符编码,我为什么要打扰它

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

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

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

要从 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';
}