为了研究 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 似乎只是将它们视为哑字节。这背后的真正科学原理是什么?
最佳答案
打印不是 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。
关于c - 如果有的话,编码在什么时候开始在 C 中发挥作用?那么如何正确打印字符串呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57066709/