我想打印单词“č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
答案 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
...十六进制。 “让我看看这些位。”