C++ 将ANSI C字符串转换为UNICODE

C++ 将ANSI C字符串转换为UNICODE,c++,string,unicode,ansi,C++,String,Unicode,Ansi,注意:我正在尝试编写自己的函数来执行此转换 我知道char是1个字节,而wchar\u 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值填充一个字节,每次跳过

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

我知道
char
是1个字节,而
wchar\u 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);
chara[]={“你好,世界!”};
wchar_t*b=重新解释铸件(a);
2) 查看函数,我看到一个
CodePage
参数,我想知道它是什么。转换是不是都一样(正如我所理解并在上面写出来的)?我原以为ASCII字符码在任何地方都是一样的,但如果我从它在Mac和Windows上的值这一事实中理解正确的话,这个论点似乎是相反的

我原以为ASCII字符码在任何地方都是一样的,但如果我从它在Mac和Windows上的值这一事实中理解正确的话,这个论点似乎是相反的

ASCII码是的,但是“扩展ASCII”字符串的高位(扰流板:没有这样的东西)映射到大量代码页中的任何一个,所有不同的编码主要用于不同的地理位置。您所采用的方法适用于简单、简单的ASCII情况,但通常不起作用,
MultiByteToWideChar
知道这一点。它将正确地从您正在使用的任何代码页重新编码到Windows混淆地称之为“Unicode”(而不是“Unicode”)的代码页,这实际上更具体地说是“UTF-16”编码

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

char a[] = { "Hello, world!" };
wchar_t* b = reinterpret_cast<wchar_t*>(a);
不。强制转换不会重新编码或更改值。这里您只是说“我保证
a
是一堆
wchar\u t
s,即使它有类型
char*
(它没有,它有数组类型,但今天已经足够接近了)

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

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

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

但是,实际上,您不想使用UTF-32。使用Windows API时,您必须使用UTF-16,但除此之外,我们通常更喜欢UTF-8,而不是
char
,这是一种好的、可移植的、灵活的、好的、好的API。(不过,您还是需要一个用于此的库。)

然后,您将决定在何处执行相关转换,和/或是否有一个从UTF-8切换到UTF-16的开关,具体取决于平台(如Windows的旧
UNICODE
宏),或者只是在任何地方运行UTF-8,直到达到Windows API边界


或者,如果您的所有输入都是ASCII,那么您实际上不需要做任何事情,只需要做您已经做的事情:在整个程序中保留ASCII,但在使用Windows API时将其转换为UTF-16,或者使用UTF-16(和
wchar\u t
s贯穿整个程序,并且没有转换。不过,请确保使用您喜爱的函数的宽字符版本(如
wprintf
)如果您这样做。

您尝试执行的操作仅适用于0..127范围内的ASCII字符代码。这些字符在Unicode中具有相同的数值,因此可以在
char
wchar\t
字符串之间复制

不,您不能只
char
数据的内存地址重新解释到
wchar\u t
*,您需要分配一个新的
wchar\u t
数组并复制值,例如:

char a[] = { "Hello, world!" };
wchar_t* b = new wchar_t[sizeof(a) * sizeof(wchar_t)];
for(size_t i = 0; i < sizeof(a); ++i) {
    b[i] = static_cast<wchar_t>(a[i]);
}
...
delete[] b;
但是,在ASCII范围之外,您需要通过字符集/代码页查找在
char
wchar\u t
之间转换数据。不同的字符集/代码页以不同的方式编码Unicode字符。
MultiByteToWideChar()
(和
WideCharToMultiByte()
)也有许多第三方库也可以处理这些转换,例如ICONV、ICU等。在某种程度上,甚至C++自己的
std::wstring_convert
std::wbuffer_convert
也可以(尽管它们在C++17以后的版本中被弃用)

例如,让我们看看代码点(
):

  • wchar\u t
    字符串中,它占用一个数值为
    0x20AC
    wchar\u t

  • 在UTF-8编码的
    char
    字符串中,它占用3个
    char
    s,其数值为
    0xE2 0x82 0xAC

  • 在Windows-1252编码的
    char
    字符串中,它占用单个
    char
    ,其数值为
    0x80

  • 在拉丁-1(ISO-8859-1)编码的
    char
    字符串中,欧元符号甚至没有指定数值

因此,一个简单的值拷贝对于非