在C中打印UTF-8字符串的字节

时间:2018-11-05 19:18:37

标签: c encoding utf-8

我想打印单词“česnek”的单个字节,期望打印7个字节,因为“č”被编码为2个字节,但确实这样做,但是会在终端打印诸如问号之类的垃圾字符。如果我打印出整数值,则会得到此序列。

-60 -115 101 115 110 101 107

为什么前两个数字为负? 这是我用来尝试的代码。

 char *utfstring = "česnek";
 for(size_t i = 0; i < strlen(utfstring); i++) {
 printf("%c ", utfstring[i]);
 }
 for(size_t i = 0; i < strlen(utfstring); i++) {
 printf("%d ", utfstring[i]);
 }

我希望前两个值是c4 8d,因为č的编码方式类似于https://www.utf8-chartable.de/unicode-utf8-table.pl?start=256&unicodeinhtml=dec

3 个答案:

答案 0 :(得分:3)

使用(unsigned char)utfstring[i]0xFF & utfstring[i]来获取十六进制输出,如下所示:

char *utfstring = u8"česnek";
for(size_t i = 0; i < strlen(utfstring); i++)
    printf("%02X ", 0xFF & utfstring[i]);

输出:

"C4 8D 65 73 6E 65 6B"

第一个字母字符č不能用UTF8中的单个字节表示。如果一次打印utfstring一个字节,则UTF8编码会中断。

它必须打印为u8"č"u8"\xC4\x8D"

通常,如果您希望将字节序列分成单独的Unicode代码点,则将需要Unicode库,例如iconv。如果您只是想查找č,请使用标准的字符串函数,例如strstr(utfstring, u8"č")

答案 1 :(得分:1)

首先,char的签名为implementation-defined。最重要的是,您要告诉printf()使用%d打印一个带签名的号码。要将它们可移植地打印为无符号数字,您需要将它们转换为unsigned并使用%u format specifier打印它们:

printf("%u ", (unsigned char) utfstring[i]);

这将处理负数,但是您还有另一个问题:C标准不需要编译器在源代码中接受UTF-8编码的字符。该标准仅保证small set of basic characters。您可能需要查看特定编译器和标准库的文档,以了解如何处理。您可能会得到UTF-8,其他一些编码或垃圾信息;无论您得到什么,它都不是便携式的。如果听起来很me脚,那是对的-是C / C ++在i18n上已经追赶很久了。

好消息是,事情正在好转。如果您的编译器支持C11,则可以并且应该利用UTF-8 string literals来可移植地将UTF-8代码点编码为字符串。

答案 2 :(得分:0)

当UTF表示形式为多字节时,您的for循环逐个字符地遍历字符值

char *utfstring = "česnek";的长度超过六个字节!因为该字符串中的第一个“字符”占用了一个以上的字节。 (UTF表示法的聪明之处在于,每个字节都以这种方式进行自我编码,这样,通过单独检查每个字节的二进制内容,您可以可靠地确定字节的“种类”以及字节的位置[如果适用]以多字节顺序显示。)

您的逻辑尝试将%c%d格式用于这些字节时,可以说,哪一种都不是最合适的。 “在这种[人类]环境中,这些不是真正的字符,也不是整数。”尝试%x ...十六进制。 “让我看看这些位。”