c - 在不使用第 3 方库的情况下基于 C 中的 char* 的多平台 Unicode 处理?

标签 c winapi unicode utf-8

以下是我发现有效的最基本示例(我知道应该定义例如 UNICODE/_UNICODE):

Linux:

#include <stdio.h>

int main() {
  char* str = "Rölf";
  printf("%s\n", str);
}

window :

#include <stdio.h>
#include <locale.h>

int main() {
  setlocale(LC_ALL, "");
  wchar_t* str = L"Rölf";
  wprintf(L"%s\n", str);
}

现在,我已经阅读了 one way of going about it基本上是“在任何地方都使用 UTF-8/char,并在进行 API 调用时担心特定于平台的转换”。

那就太好了——让用户提供 char* 作为我的库的输入并“简单地”转换它。所以我尝试了以下基于 this example 的代码片段(我也在其他地方看到过它的变体)。如果这真的有效,那将是惊人的。但事实并非如此:

  char* str = u8"Rölf";
  int len = mbstowcs(NULL, str, 0) + 1;
  wchar_t wstr[len];
  mbstowcs(wstr, str, len);
  wprintf(L"%s\n", wstr);

我也偶然发现了有关控制台字体的讨论以及渲染错误的原因,因此为了证明这不是控制台问题 - 以下内容也不起作用(好吧 - L""文字起作用。转换后的 u8 文字没有):

  MessageBoxW(NULL, wstr, L"Rölf", MB_OK);

enter image description here

我是否误解了转换过程?有没有办法完成这项工作? (不使用例如 ICU)

最佳答案

mbstowcs 函数将字符串以当前语言环境编码 转换为 wchar_t[],而不是从 UTF-8(除非编码是 UTF-8)。在 2018 年 4 月之后的 Windows 10 或更高版本中,您实际上可以修复 Windows 以使用 UTF-8 作为普通 char[] 字符串的编码,或者作为全局设置,或者可能通过调用 _setmbcp(65001)。然而,由于可疑的历史原因,旧版本的 Windows 明确禁止这样做。

无论如何,如果不是因为 MSVC 的 wprintf 中的错误,你称为“Windows”的代码的第二个版本应该可以在任意系统上工作:它们具有 的含义%ls%s 向后用于广泛的 stdio 函数。在标准 C 中,您需要 %ls 来格式化 wchar_t[] 字符串。但实际上根本没有理由在那里使用 wprintf ,事实上 wprintf 是非常有问题的,因为你不能将它与面向字节的 stdio 混合使用(这样做会调用 undefined行为)。更好的做法是:

#include <stdio.h>
#include <locale.h>

int main() {
  setlocale(LC_ALL, "");
  wchar_t* str = L"Rölf";
  printf("%ls\n", str);
}

并且这个版本应该可以在 Windows 和符合标准的 C 实现上正常工作,因为对于面向字节的 printf 函数,MSVC 没有 %s 的含义> 和 %ls 颠倒了。

如果你真的想,你也可以使用你的代码的第三个版本的变体,但你不能使用 mbstowcs 从 UTF-8 转换为 wchar_t。相反,您需要:

  1. 假设 wchar_t 是 Unicode 编码的,并使用您自己的(或第三方库的)UTF-8 解码器将 UTF-8 代码点转换为 Unicode 代码点。但这是一个错误的假设,因为 MSVC 也不符合标准,因为它对 wchar_t 使用 UTF-16(C 明确禁止“multi-wchar_t-characters 因为 mb/wc API 本质上与它们不兼容),而不是 Unicode 代码点值(相当于 UTF-32)。

  2. 使用您自己的(或第三方库的)UTF-8 解码器从 UTF-8 转换为 uchar32_t (UTF-32),然后使用 c32rtomb 转换为 wchar_t[]

  3. 使用 iconv(POSIX 系统上的标准;在 Windows 上作为第三方库提供)直接从 UTF-8 转换为 wchar_t


适用于 Windows 10 版本 1803+ 的 UTF8 选项

enter image description here

关于c - 在不使用第 3 方库的情况下基于 C 中的 char* 的多平台 Unicode 处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51687784/

相关文章:

c - 用于计算文件中的行数、字符或单词数的程序

c - 什么 's wrong with this "简单“代码

c++ - GetCursorPos 工作正常但 GetPhysicalCursorPos "not declared in this scope"?

c++ - 从 C++ 解压 ZIP 的最简单方法?

python - Openpyxl Unicode 值

c - 仅传递空格时 fgets 给我一个段错误

c - dup 返回值始终为零

winapi - 为什么 CreateProcessWithTokenW 因 ERROR_ACCESS_DENIED 而失败

emacs - 从 Emacs 在 Markdown 中呈现 unicode 字符

python - Flask URL路由编码问题