c - 如果有的话,编码在什么时候开始在 C 中发挥作用?那么如何正确打印字符串呢?

标签 c character-encoding

为了研究 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/

相关文章:

python - 在 Python 中处理 UTF-8 数字

Windows 10 CLI 终端上的 git log 输出编码问题

c - 在记事本中打开由 C 程序创建的文本文件的错误显示

c - 用户读取未定义大小数组的数字

c - 阅读 C 中的图表?

c - 使用函数通过 strcmp 对 argv 值进行排序

java - HttpUrlConnection 读取输入流 - 不同的输出结果

C - 增量不更新变量值

c - 如何将 '\0' 转换为 const void*?

在 Windows 上使用 UTF-8 开发 R 包