要研究C如何处理UTF-8 / Unicode字符,我做了一个小实验。
这不是我目前正在尝试解决任何特殊问题,但是我知道Java以对编码员透明的方式处理整个编码情况,我想知道C的水平如何,这要低得多,对待字符。
以下测试似乎表明C完全不关心编码方面的问题,因为这取决于显示设备是否知道在屏幕上显示字符时如何解释字符序列。以后的测试(在打印由_
包围的字符时)似乎特别有用?
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "João"; // ã does not belong to the standard
// (or extended) ASCII characters
printf("number of chars = %d\n", (int)strlen(str)); // 5
int len = 0;
while (str[len] != '\0')
len++;
printf("number of bytes = %d\n", len); // 5
for (int i = 0; i < len; i++)
printf("%c", str[i]);
puts("");
// "João"
for (int i = 0; i < len; i++)
printf("_%c_", str[i]);
puts("");
// _J__o__�__�__o_ -> wow!!!
str[2] = 'X'; // let's change this special character
// and see what happens
for (int i = 0; i < len; i++)
printf("%c", str[i]);
puts("");
// JoX�o
for (int i = 0; i < len; i++)
printf("_%c_", str[i]);
puts("");
// _J__o__X__�__o_
}
我了解ASCII / UTF-8的工作方式,我不确定的是什么时候将字符解释为“复合”字符,因为C似乎只是将它们视为哑字节。真正的科学依据是什么?
答案 0 :(得分:1)
打印不是C的功能,而是显示上下文的功能,无论是什么功能。对于终端,有UTF-8解码功能,可将原始字符数据映射到要使用特定字体在屏幕上显示的字符。在图形应用程序中会发生类似的显示逻辑,但是与比例字体宽度,连字,连字和许多其他印刷方面的复杂性有关。
在内部,这通常是通过先将UTF-8解码为某种中间形式(例如UTF-16或UTF-32)来完成的,以进行查找。用非常简单的术语来说,字体中的每个字符都有一个Unicode标识符。实际上,这要复杂得多,因为存在字符变体的空间,并且多个字符可能由字体中的单个字符表示,例如“ fi”和“ ff” ligatures。 Unicode允许的重音字符(例如“ç”)可以是字符的组合。那就是Zalgo text之类的东西出现的地方:您通常可以将真正荒谬的Unicode“组合字符”数量堆叠在一起成为单个输出字符。
排版是一个复杂的世界,需要正确渲染的复杂库。
您可以使用C处理UTF-8数据,但只能使用特殊的库。标准库中C附带的任何内容都无法理解它们,对于C来说,它只是一系列字节,并且出于长度目的,它假定字节等效于字符。即strlen
,并且这样的工作以字节为单位,而不是字符。
C ++对字节和字符之间的区别有更好的支持。其他语言甚至提供了更好的支持,例如Swift等语言特别支持UTF-8和一般的Unicode。
答案 1 :(得分:0)
printf("_%c_", str[i]);
打印与每个str[i]
相关的字符-一次打印一个。
通过char str[i]
函数传递时,int
的值将转换为...
。然后,按照int
的指示,将unsigned char
值转换为"%c"
并“并写入结果字符”。
char str[] = "João";
不一定指定UTF8序列。在实现细节中。一种指定的方法是从C11(或C99)开始使用char str[] = u8"João";
。
printf()
没有指定直接打印 UTF8搅拌的方法。