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

C - How to convert wide char Japanese characters to UTF-8?

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

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);

然后,根据其他答案,但也成功地从 json UTF-8 转换为宽字符,尝试了如下相反的函数,但目标缓冲区 dest 仅包含垃圾字符:

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_t) 是 ササササササササササササササササ 存储在 japanese[i].name 中(结构中的 wchar_t*)。 Objective是使用cJSON的cJSON_CreateString将值保存在UTF-8编码的json文件中。

问题:在 C(而非 C++)中将日语从 wchar_t 转换为 UTF-8 字符的正确方法是什么?

您的 wcstombs_s() 代码将错误的值传递给 sizeInBytes 参数:

sizeInBytes

The size in bytes of the mbstr buffer.

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

Unicode 代码点在 UTF-16 中编码(wchar_t 字符串在 Windows 中编码)每个使用 2 或 4 个字节,在 UTF-8 中每个使用 1-4 个字节,取决于它们的价值。 U+0080..U+FFFF 范围内的 Unicode 代码点在 UTF-8 中占用的字节数比在 UTF-16 中占用的字节多,因此您的 japanese_char 缓冲区实际分配的空间可能比 japanese[i].name 数据。就像您可以调用 WideCharToMultiByte() 来确定所需的目标缓冲区大小一样,您可以使用 wcstombs_s().

做同样的事情
size_t len = 0;
wcstombs_s(&len, NULL, 0, japanese[i].name, _TRUNCATE);
if (len == 0)
    exit(EXIT_FAILURE);
char* japanese_char = malloc(len);
if (!japanese_char)
    exit(EXIT_FAILURE);
wcstombs_s(&len, japanese_char, len, japanese[i].name, _TRUNCATE);
...
free(japanese_char);

由于您向 cchWideChar 参数传递了明确的大小,因此您的 WideCharToMultiByte() 代码不是空终止 dest

cchWideChar

Size, in characters, of the string indicated by lpWideCharStr. Alternatively, this parameter can be set to -1 if the string is null-terminated. If cchWideChar is set to 0, the function fails.

If this parameter is -1, the function processes the entire input string, including the terminating null character. Therefore, the resulting character string has a terminating null character, and the length returned by the function includes this character.

If this parameter is set to a positive integer, the function processes exactly the specified number of characters. If the provided size does not include a terminating null character, the resulting character string is not null-terminated, and the returned length does not include this character.

cJSON_CreateString() 需要一个以 null 结尾的 char* 字符串。所以你需要:

  • 将 +1 添加到 calloc()num 参数以解决缺少的空终止符。
size_t wcsChars = wcslen(japanese[i].name);
size_t len = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, NULL, 0, NULL, NULL);
char* japanese_char = malloc(len + 1);
if (!japanese_char)
    exit(EXIT_FAILURE);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, japanese_char, len, NULL, NULL);
japanese_char[len] = '[=11=]';
...
free(japanese_char);
  • 将+1添加到wcslen()的return值,或将WideCharToMultiByte()cchWideChar参数设置为-1,以在输出中包含空终止符.
size_t wcsChars = wcslen(japanese[i].name) + 1;
size_t len = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, NULL, 0, NULL, NULL);
if (len == 0)
    exit(EXIT_FAILURE);
char* japanese_char = malloc(len);
if (!japanese_char)
    exit(EXIT_FAILURE);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, japanese_char, len, NULL, NULL);
...
free(japanese_char);
size_t len = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, -1, NULL, 0, NULL, NULL);
if (len == 0)
    exit(EXIT_FAILURE);
char* japanese_char = malloc(len);
if (!japanese)
    exit(EXIT_FAILURE);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, -1, japanese_char, len, NULL, NULL);
...
free(dest);