C-如何将宽字符日语字符转换为UTF-8?

C-如何将宽字符日语字符转换为UTF-8?,c,json,encoding,utf-8,cjson,C,Json,Encoding,Utf 8,Cjson,尝试将宽字符中存储的日语字符转换为UTF-8,以便使用cJSON库将值存储在json文件中。首先尝试使用wcstombs\u,但显然不支持日语字符: size_t len = wcslen(japanese[i].name) + 1; char* japanese_char = malloc(len); if (japanese_char == NULL) { exit(EXIT_FAILURE); } size_t sz; wcstombs_s(&sz, japanese_ch

尝试将宽字符中存储的日语字符转换为UTF-8,以便使用cJSON库将值存储在json文件中。首先尝试使用
wcstombs\u
,但显然不支持日语字符:

size_t len = wcslen(japanese[i].name) + 1;
char* japanese_char = malloc(len);
if (japanese_char == NULL) {
    exit(EXIT_FAILURE);
}
size_t sz;
wcstombs_s(&sz, japanese_char, len, japanese[i].name, _TRUNCATE);
size_t wcsChars = wcslen(japanese[i].name);
size_t sizeRequired = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, NULL, 0, NULL, NULL);
char* dest = calloc(sizeRequired, 1);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, dest, sizeRequired, NULL, NULL);
free(dest);
然后,根据其他答案,但在从json UTF-8到宽字符的成功转换中,尝试了如下相反的函数,但目标缓冲区
dest
仅包含垃圾字符:

size_t len = wcslen(japanese[i].name) + 1;
char* japanese_char = malloc(len);
if (japanese_char == NULL) {
    exit(EXIT_FAILURE);
}
size_t sz;
wcstombs_s(&sz, japanese_char, len, japanese[i].name, _TRUNCATE);
size_t wcsChars = wcslen(japanese[i].name);
size_t sizeRequired = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, NULL, 0, NULL, NULL);
char* dest = calloc(sizeRequired, 1);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, dest, sizeRequired, NULL, NULL);
free(dest);
我试图转换的宽字符(
wchar\u t
)是
ササササササササササササササササ存储在
日语[i]中。名称
(结构中的
wchar\u t*
)。目标是使用cJSON的
cJSON_CreateString
将值保存在UTF-8编码的json文件中

问题:将日语从wchar\u t转换为C(而不是C++)中的UTF-8字符的正确方法是什么?

您的
wcstombs\u s()
代码将错误的值传递给
大小字节
参数:

sizeInBytes

缓冲区的大小(以字节为单位)

您传入的是
日文[i].name的字符计数,而不是
日文字符的分配字节计数。它们不是相同的值

Unicode码点在UTF-16中使用2或4个字节进行编码(Windows上的编码字符串是什么),在UTF-8中使用1-4个字节,具体取决于它们的值。
U+0080..U+FFFF
范围内的Unicode码点在UTF-8中比在UTF-16中占用更多字节,因此可能需要实际分配的
japanese_char
缓冲区比
japanese[i].name
数据大。正如您可以调用
WideCharToMultiByte()
来确定所需的目标缓冲区大小一样,您也可以使用
wcstombs\u s()
执行相同的操作

size\u t len=0;
wcstombs_s(&len,NULL,0,日语[i]。名称,_TRUNCATE);
如果(len==0)
退出(退出失败);
字符*日语字符=malloc(len);
如果(!日语字符)
退出(退出失败);
wcstombs_s(&len,japanese_char,len,japanese[i]。名称,_TRUNCATE);
...
免费(日文);

由于将显式大小传递给
cchwidechart
参数,因此您的
WideCharToMultiByte()
代码不是空的

cchWideChar

lpWideCharStr指示的字符串的大小(以字符为单位)。或者,如果字符串以null结尾,则可以将此参数设置为-1。如果cchWideChar设置为0,则函数失败

如果此参数为-1,则函数将处理整个输入字符串,包括终止的空字符。因此,结果字符串有一个终止的空字符,函数返回的长度包括这个字符

如果此参数设置为正整数,则函数将精确处理指定数量的字符。如果提供的大小不包括以null结尾的字符,则生成的字符串不会以null结尾,并且返回的长度不包括此字符。

cJSON\u CreateString()
需要以null结尾的
char*
字符串。因此,您需要:

  • 将+1添加到
    calloc()
    num
    参数中,以说明缺少的空终止符
size\u t wcsChars=wcslen(日语[i].name);
size\u t len=WideCharToMultiByte(CP\u UTF8,0,日语[i]。名称,wcsChars,NULL,0,NULL,NULL);
char*japanese_char=malloc(len+1);
如果(!日语字符)
退出(退出失败);
WideChartMultibyte(CP_UTF8,0,日语[i]。名称,wcsChars,日语字符,len,NULL,NULL);
日语字符[len]='\0';
...
免费(日文);
  • 将+1添加到
    wcslen()
    的返回值,或将
    WideCharToMultiByte()
    cchWideChar
    参数设置为-1,以在输出中包含空终止符
size\u t wcsChars=wcslen(日语[i].name)+1;
size\u t len=WideCharToMultiByte(CP\u UTF8,0,日语[i]。名称,wcsChars,NULL,0,NULL,NULL);
如果(len==0)
退出(退出失败);
字符*日语字符=malloc(len);
如果(!日语字符)
退出(退出失败);
WideChartMultibyte(CP_UTF8,0,日语[i]。名称,wcsChars,日语字符,len,NULL,NULL);
...
免费(日文);
size\u t len=WideCharToMultiByte(CP\u UTF8,0,日语[i]。名称,-1,NULL,0,NULL,NULL);
如果(len==0)
退出(退出失败);
字符*日语字符=malloc(len);
如果(!日语)
退出(退出失败);
WideChartMultibyte(CP_UTF8,0,日语[i]。名称,-1,日语字符,len,NULL,NULL);
...
免费(目的地);
它可以工作(而且我忘了在VS watch窗口中添加
,s8
,以查看UTF8编码值,但没有您的修复,它是错误的:我有
ササササササササササササササササ6Cfp
)。再次感谢您的详细回答。