我从内存中的结构中得到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包含'♪'。
答案 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';
}