如何获取 C 中 char * 下存储的多字节字符的 unicode 值?

How to get unicode value of multibyte character stored under char * in C?

假设我不使用 C11 中的 <uchar.h> 而有这样的东西

char *a = "Ā";

我怎样才能得到这个字符的 unicode 值(它是 256)?做这样的事情:

int *a_value = (int *)a;
printf("%d\n", *a_value);

无效。

这个字符在内存中是怎么写的? gdb 显示:

loc a = 0x555555556004 "Ā": -60 '4'

但完全不明白它到底是什么意思。

我检查了 a 的大小,它是 2 个字节,这没问题,但是

printf("%d\n", a[0]);
printf("%d\n", a[1]);

也不行。它给了我 -60 和 -128。

值编码为 UTF-8。

256 在二进制中是 100000000(9 位)。它多于 7 位(但少于 12 位),因此需要 2 个字节以 UTF-8 编码。

第一个字节将包含前 5 位,第二个字节将包含最后 6 位。

所以,11 位的二进制 256 又是 0010000000000100 后跟 000000

最终 UTF-8 第一个字节 11000100 ... 110 + 00100
最终 UTF-8 第二字节 10000000 ... 10 + 000000

11000100十进制为196,或者考虑MSB为符号位:-60
10000000 十进制为 128,或者考虑 MSB 为符号位:-128

Wikipedia article

中阅读有关 UTF-8 编码的更多信息

还有两件事:

(1) 你得到那些奇怪的数字是因为你机器上的普通字符(像许多字符一样)显然是有符号的。您可以通过转换为 unsigned char:

来查看“真实”字节
char *a = "Ā";
printf("%u %u\n", ((unsigned char *)a)[0], ((unsigned char *)a)[1]);
printf("%x %x\n", ((unsigned char *)a)[0], ((unsigned char *)a)[1]);

或一直使用 unsigned char

unsigned char *u = "Ā";
printf("%x %x\n", u[0], u[1]);

%u版本打印196 128%x版本打印c4 80.

(2) 我不确定你所说的“不使用 C11 中的 <uchar.h>”是什么意思,但是如果你不想手动进行 UTF-8 转换,你可以转换一个通过使用来自 <stdlib.h>:

的库函数 mbtowc 将“多字节字符串”(几乎总是 UTF-8)转换为宽字符或 Unicode 字符
wchar_t wc;
mbtowc(&wc, a, strlen(a));
printf("%d %x\n", wc, wc);

这会在我的机器上打印 256 100,因为 Ā 是 U+0100。

另一个有用的函数是 mbstowcs,它可以同时处理多个字符:

char *mbs = "Daß ist sehr schön";
printf("%s\n", mbs);
wchar_t wcs[20];
int n = mbstowcs(wcs, mbs, 20);
for(int i = 0; i < n; i++)
    printf("%3d %x %lc\n", wcs[i], wcs[i], wcs[i]);

但是,当使用 mbtowcmbstowcs 等函数时,您必须记住它们 而不是 必须处理 UTF-8 和 Unicode。除了 Unicode,还有宽字符编码,除了 UTF-8,还有多字节表示。事实上,为了让这些功能在我的机器上“正确”工作,我必须先调用

setlocale(LC_CTYPE, "");

告诉他们可以使用我的语言环境设置(即 en_US.UTF-8),而不是 假定 Unicode 的默认“C”语言环境。