char如何存储两个数字?

V. *_*hin 4 c char cyrillic

下一个案例:我有西里尔符号"б".运行下一个代码:

int main() {
    char c;
    scanf("%c", &c);
    printf("%d\n", c);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

显示-48.但是当我调试这个变量时c,它会显示下一个:-48 '\320'在此输入图像描述.

那么这是如何工作的呢?这是一个指向2长度数组的指针吗?或者它如何存储两个数字?

Mat*_*lia 5

char变量既可以被用来存储一个小1个在一些不那么良好定义的,通常-基于ASCII编码整数,或字符(更恰当地,代码单位).在这里,调试器只是试图通过显示内容的两个(有争议的)有意义的表示来提供帮助c.


让我们想象一下你实际上写的a而不是?; 在这种情况下,调试器会写类似的东西

c = {char} 97 'a'
Run Code Online (Sandbox Code Playgroud)

因为存储的实际数字c是97,并且解码为ASCII,它对应于字母a.

不幸的是,你可以将每个可能的字符放在一个8位char值中的想法是完全有缺陷的,因此现在使用的最广泛的编码(UTF-8)恰好是你机器上使用的编码,需要多个代码单位(≈bytes)表示单个代码点(≈逻辑字符)(此问题中的更多细节).特别地,б表示为两个字节的字符串,即字节0xD0和0xB1.

C对UTF-8或代码点一无所知; 如果指定%cscanf,则它会读入单个字节,而不管它是否足以表示完整的UTF-8代码点.因此,只有第一个字节被读取,并且c只包含0xD0值; 0xB1仍在缓冲区中,尚未读取.

回到调试器显示的值,首先必须注意的是,在您的平台上(不幸的是,在许多平台上),char已签名.因此,0xD0字节被解释为带符号的值为-48(实际上,0xD0 = 208,其在127处"环绕"; 208-256 = -48).

至于'\320':这里的调试器想要显示该值的ASCII表示; 但是,字节0xD0在ASCII字符范围2之外,所以在这里它会显示一个转义序列.您可能熟悉'\n'代表换行符或\0NUL字符; 通常,\在C中后跟一到三位数表示具有相应八进制值的字节; 0320确实是208的八进制,对于0xD0是十进制的.

所以,这里没有任何谜:c仍然包含一个单独的值(只是你角色的"一半"); 你所看到的只是其内容的两个(同样不方便)的表示.


笔记

  1. 在大多数平台上,[ - 128,127]或[0,255],取决于char(不幸的是,实现定义的)的签名.
  2. 实际上,UTF-8 通过仅使用具有高位集(未使用ASCII)的字节来扩展 ASCII,用于其多字节序列; 这可以确保它们不会被误解为ASCII文本.