Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
char如何存储两个数字?_C_Char_Cyrillic - Fatal编程技术网

char如何存储两个数字?

char如何存储两个数字?,c,char,cyrillic,C,Char,Cyrillic,下一个例子:我有西里尔字母“б”。运行下一个代码: int main() { char c; scanf("%c", &c); printf("%d\n", c); return 0; } 显示-48。但是,当我调试这个变量c时,它接下来会显示:-48'\320' 那么这是如何工作的呢?这是指向2长度数组的指针吗?或者它如何能够存储两个数字?西里尔字符[使用utf-8]是多字节chars。十六进制的“字符”是字符串/数组: D0B1 因此,您不能使用%

下一个例子:我有西里尔字母“б”。运行下一个代码:

int main() {
    char c;
    scanf("%c", &c);
    printf("%d\n", c);
    return 0;
}
显示
-48
。但是,当我调试这个变量
c
时,它接下来会显示:
-48'\320'


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

西里尔字符[使用
utf-8
]是多字节
char
s。十六进制的“字符”是字符串/数组:

D0B1
因此,您不能使用
%c
检索它。您需要使用
%s

#include <stdio.h>

int
main(void)
{
    char utf[1000];
    char *cp;

    scanf("%s", utf);
    printf("%s\n", utf);

    for (cp = utf;  *cp != 0;  ++cp)
        printf(" %2.2X",*cp & 0xFF);
    printf("\n");

    return 0;
}

更新:


那么,这个字符是如何定位在内存中的呢?当涉及西里尔文时,C是否能够生成字符2字节

首先,请参见:

通过键盘输入西里尔字符时,键盘硬件、终端仿真器程序和文本编辑器的组合将键盘序列转换为
utf-8
序列,并最终生成正在编辑的文本文件

你所说的西里尔字符就是
utf-8
所说的“代码点”

当放置在文本文件中时,代码点将变成如上所述的多字节序列

scanf
printf
对此一无所知。例如,
printf
只发送字符串:
XXXXXXX\0
,其中X可以是单个ASCII字符或多字符代码点的一部分

由终端仿真器来理解这一点,并从utf-8字体集中输出正确的字符[其中包含西里尔字母、希腊字母、法语字母等]

诸如
strlen
strcpy
之类的函数只关心尾随的0x00 EOS字符。因此,从技术上讲,它们可以工作,并且通常可以像ASCII字符串一样轻松地通过
utf-8
字符串,因为EOS是相同的

但是,
strlen
将为您提供字符串中
char
的编号。例如,在上面的
strlen
中将返回2,因为它将
D0
B1
作为
char
数组中的单独
char
值进行计数

而且,
strchr
[可能]不会起作用。您可能希望在
utf-8
中使用
strstr

当然,其中西里尔字符只有一个代码点,因此
utf-8
aware函数必须以不同的方式处理数组。例如,在计算代码点的数量时,他们需要看到
D0B1
是单个代码点,因此结果计数为一

一般规则是ASCII(
0x01-0x7F
)直接映射到
utf-8
,作为单个
char
s。设置高位(
0x80
)的任何内容都是
utf-8
多字节代码点的一部分。
0x40
用于指示序列的起始[最左边]字节。序列中所有剩余字节的格式(以位为单位):
10xxxxxx
。序列中剩余字节的数量由起始字节中前缀1位的数量表示。下表显示了如何解码字节序列(
x
表示作为代码点值一部分的位):


因此,
utf-8
aware功能可以在正向或反向扫描时检测并跳过代码点。并且,可以区分两个[或多个]相邻的多字节代码点。

一个
char
变量可以用于存储一个小整数,或者在一些定义不太明确、通常基于ASCII的编码中存储一个字符(更恰当地说,是代码单位)。这里,调试器只是试图通过显示
c
内容的两个(有争议的)有意义的表示来提供帮助


让我们想象一下,您实际上编写了
a
,而不是
б
;在这种情况下,调试器将编写如下内容

c = {char} 97 'a'
因为
c
中存储的实际数字是97,并且被解码为ASCII,它对应于字母
a

不幸的是,在一个8位
char
值中可以容纳所有可能的字符的想法是完全有缺陷的,因此目前使用最广泛的编码(UTF-8)需要多个代码单元,而UTF-8恰好是您机器上使用的编码(≈字节)来表示单个代码点(≈逻辑字符(更多细节)。具体而言,б表示为两个字节的字符串,即字节0xD0和0xB1

C对UTF-8或代码点一无所知;如果将
%c
指定为
scanf
,则无论是否足以表示完整的UTF-8码点,它都以单个字节读取。因此,只有第一个字节被读取,
c
只包含0xD0值;0xB1仍在缓冲区中,尚未读取

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

至于
'\320'
:这里的调试器希望显示该值的ASCII表示形式;但是,字节0xD0不在ASCII字符范围2内,因此在这里它将以转义序列显示。您可能熟悉用
'\n'
表示换行符,或用
\0
表示NUL字符;一般来说,C中一个
\
后跟一到三位数字表示具有相应八进制值的字节
0320实际上是208的八进制,这是0xD0的十进制

因此,这里没有什么神秘之处:
c
仍然包含一个值(它只是角色的“一半”);您看到的只是其内容的两种(同样不方便)表示


注释

  • 在大多数平台上
    # of    Start       Remaining Bytes
    bytes   Byte
    1       0xxxxxxx
    2       110xxxxx    10xxxxxx
    3       1110xxxx    10xxxxxx    10xxxxxx
    4       11110xxx    10xxxxxx    10xxxxxx    10xxxxxx
    
    c = {char} 97 'a'