【问题标题】:How to get unicode value of multibyte character stored under char * in C?如何获取存储在 C 中 char * 下的多字节字符的 unicode 值?
【发布时间】:2021-05-29 14:58:38
【问题描述】:

假设我不使用 C11 中的 <uchar.h> 并且有类似的东西

char *a = "Ā";

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

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

没用。

这个字符是如何写入内存的? gdb 向我展示:

loc a = 0x555555556004 "Ā": -60 '\304'

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

我检查了a 的大小,它是 2 个字节,这没关系,但是这样做

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

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

【问题讨论】:

    标签: c unicode


    【解决方案1】:

    还有两件事:

    (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 转换,您可以转换“多字节字符串”使用库函数 mbtowc 来自 <stdlib.h>

    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),而不是默认的“C”语言环境,它假定为 Unicode。

    【讨论】:

      【解决方案2】:

      该值被编码为 UTF-8。

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

      第一个字节有前 5 位,第二个字节有最后 6 位。

      所以,256 再次以 11 位二进制表示 0010000000000100 后跟 000000

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

      十进制的11000100196,或将MSB 视为符号位:-60
      10000000 十进制为128,或将MSB 视为符号位:-128

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

      【讨论】:

      • 非常感谢!现在我明白了。值得一提的是,第一个字节的 110 表示这个字符用 2 个字节编码,第二个字节的 10 表示它是前一个字符的延续。
      猜你喜欢
      • 1970-01-01
      • 2017-08-25
      • 2018-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-31
      • 1970-01-01
      相关资源
      最近更新 更多