首页 > 解决方案 > 将 ANSI C 字符串转换为 UNICODE

问题描述

注意:我正在尝试编写自己的函数来执行此转换

我知道 achar是 1 个字节,而 awchar_t是 2 个字节。

所以这就是转换的发生方式:

1) 输入文字

Hello, world

2) 获取字符串的字节

48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21

3) 分配两倍于字节数的内存

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

4)用ANSI值填充一个字节,一次跳过一个字节

48 00 65 00 6c 00 6c 00 6f 00 2c 00 20 00 77 00 6f 00 72 00 6c 00 64 00 21 00

关于这个过程,我有几个问题:

1) 我可以简单地将一个 ANSI 字符串转换为 UNICODE 并让它复制上面的确切过程,还是它会简单地用 ANSI 字节填充字节的前半部分并将其余部分保留为 0?

char a[] = { "Hello, world!" };
wchar_t* b = reinterpret_cast<wchar_t*>(a);

2) 查看MultiByteToWideChar函数,我看到一个CodePage参数,我想知道它是什么。转换不都是一样的吗(据我了解并在上面写出来)?我认为 ASCII 字符代码在所有地方都是相同的,但是如果我从它那里有 Mac 和 Windows 的值这一事实正确理解的话,这个论点似乎不是这样。

标签: c++stringunicodeansi

解决方案


我认为 ASCII 字符代码在所有地方都是相同的,但是如果我从它那里有 Mac 和 Windows 的值这一事实正确理解的话,这个论点似乎不是这样。

ASCII 代码是,是的,但是“扩展 ASCII”字符串的高位(剧透:没有这样的东西)映射到大量代码页中的任何一个,所有不同的编码主要用于不同的地理区域。您采用的方法适用于简单的纯 ASCII 大小写,但它通常不起作用,并且MultiByteToWideChar知道这一点。它将正确地从您使用的任何代码页重新编码为 Windows 令人困惑地称为“Unicode”(而不是“UNICODE”),这实际上是更具体地说是“UTF-16”编码。

我可以简单地将一个 ANSI 字符串转换为 UNICODE 并让它复制上面的确切过程,还是只是用 ANSI 字节填充字节的前半部分并将其余部分保留为 0?

不会。演员表不会重新编码或更改值。你只是说“我保证这a是一堆wchar_ts,即使它有类型char*(它没有,它有数组类型,但对于今天来说足够接近)。

如果您使用 ,该代码实际上具有未定义的行为,b因为您违反了别名规则(您可以T通过 a检查 a char*,但不能将 achar[]视为T您从未创建的一些)。但是,如果没有,您会发现您的“字符串”现在只有一半长度,而且很可能是一个无效的 UTF-16 序列,无法在任何地方正确呈现。

因此,如果我想支持 UTF-32,我将不得不为字符串创建自己的包装器,因为 wchar_t 只有 2 个字节长并且我需要 4 个字节,而且我也无法使用 printf 打印它,对吗?

从技术上讲,是的(尽管你会使用像libicu这样的库而不是自己滚动)。

但是,实际上,您不想使用 UTF-32。使用 Windows API 时,您会被 UTF-16 困住,但除此之外,我们通常更喜欢 UTF-8 而不是 UTF-8 char,它很好、可移植、灵活、好用。(不过,您将再次需要一个库。)

然后由您决定在哪里执行相关转换,和/或您是否有一个根据平台(如 Windows 的旧UNICODE宏)从 UTF-8 切换到 UTF-16 的开关,或者只是运行 UTF- 8 无处不在,直到您达到 Windows API 边界。

或者,如果您的所有输入都是您所暗示的 ASCII,那么您实际上不需要做任何事情,除了您已经做的事情:或者在整个程序中保留您的 ASCII,但在使用 Windows API 时将其转换为 UTF-16,或者wchar_t在整个程序中使用 UTF-16 (和s 并且没有转换。确保使用你最喜欢的函数的宽字符版本,但wprintf如果你走那条路(比如 )。


推荐阅读