签署一个字符是什么意思?
鉴于有符号和无符号整数使用相同的寄存器等,并且只是不同地解释位模式,C字符基本上只是8位整数,C中有符号和无符号字符之间的区别是什么? 我理解char的签名是实现定义的,我根本无法理解它是如何产生影响的,至少当char用于保存字符串而不是数学时。
它不会对字符串产生影响。 但是在C语言中,你可以使用char来进行数学运算,这会产生影响。
实际上,当在受限制的内存环境中工作时,如嵌入式8位应用程序,通常会使用char来进行数学运算,然后它会产生很大的不同。 这是因为C中默认没有byte
类型。
就他们所代表的价值而言:
无符号的字符:
- 跨越值范围
0..255 (00000000..11111111)
-
值在低边缘溢出:
0 - 1 = 255 (00000000 - 00000001 = 11111111)
-
值在高边缘溢出:
255 + 1 = 0 (11111111 + 00000001 = 00000000)
-
按位右移运算符(
>>
)执行逻辑移位:10000000 >> 1 = 01000000 (128 / 2 = 64)
签名字符:
- 跨越值范围
-128..127 (10000000..01111111)
-
值在低边缘溢出:
-128 - 1 = 127 (10000000 - 00000001 = 01111111)
-
值在高边缘溢出:
127 + 1 = -128 (01111111 + 00000001 = 10000000)
-
按位右移运算符(
>>
)执行算术移位:10000000 >> 1 = 11000000 (-128 / 2 = -64)
我包含了二进制表示,以表明值包装行为是纯粹的,一致的二进制算术,并且与正在签名/未签名的char(期望右移)无关。
更新
评论中提到的一些特定于实现的行为:
- char!= signed char。 没有“signed”或“unsinged”的类型“char”是实现定义的,这意味着它可以表现为有符号或无符号类型。
- 有符号整数溢出导致程序可以执行任何操作的未定义行为,包括转储核心或超出缓冲区。
#include int main(int argc, char** argv) { char a = 'A'; char b = 0xFF; signed char sa = 'A'; signed char sb = 0xFF; unsigned char ua = 'A'; unsigned char ub = 0xFF; printf("a > b: %s\n", a > b ? "true" : "false"); printf("sa > sb: %s\n", sa > sb ? "true" : "false"); printf("ua > ub: %s\n", ua > ub ? "true" : "false"); return 0; } [root]# ./a.out a > b: true sa > sb: true ua > ub: false
排序字符串时很重要。
有一些区别。 最重要的是,如果通过为char分配一个太大或小的整数来溢出char的有效范围,并且char被签名,则结果值是实现定义的,甚至一些信号(在C中)可能会boost,就像所有签名类型一样。 与你为无符号字符分配太大或太小的东西的情况形成对比:值环绕,你将获得精确定义的语义。 例如,将-1分配给unsigned char,您将获得UCHAR_MAX。 所以每当你有一个从0到2 ^ CHAR_BIT的数字的字节时,你应该使用unsigned char来存储它。
传递给vararg函数时,符号也会有所不同:
char c = getSomeCharacter(); // returns 0..255 printf("%d\n", c);
假设分配给c的值太大而无法表示char,并且机器使用两个补码。 许多实现都适用于为char指定过大值的情况,因为位模式不会更改。 如果int能够表示char的所有值(对于大多数实现来说都是如此),那么在传递给printf之前,char将被提升为int。 因此,传递的内容的价值将是负面的。 升级到int将保留该符号。 所以你会得到负面结果。 但是,如果char是无符号的,则该值是无符号的,并且提升为int将产生正int。 您可以使用unsigned char,然后您将获得对变量赋值的精确定义行为,并传递给printf,然后printf将打印出正面的内容。
请注意,char,unsigned和signed char都至少为 8位宽。 不要求char 恰好是 8位宽。 但是,对于大多数系统来说都是如此,但对于某些系统,你会发现它们使用32位字符。 C和C ++中的字节定义为char的大小,因此C中的字节也不总是精确的8位。
另一个区别是,在C中,unsigned char必须没有填充位。 也就是说,如果发现CHAR_BIT为8,则无符号字符的值必须介于0 .. 2 ^ CHAR_BIT-1之间。 如果它没有签名,那对于char也是如此。 对于signed char,即使您知道编译器如何实现符号(二进制补码或其他选项),也不能假设有关值范围的任何内容,可能会有未使用的填充位。 在C ++中,所有三种字符类型都没有填充位。
“签署一个字符是什么意思?”
传统上,ASCII字符集由7位字符编码组成。 (与8位EBCIDIC相反。)
在设计和实现C语言时,这是一个重要问题。 (由于各种原因,例如通过串行调制解调器设备进行数据传输。)额外位具有奇偶校验等用途。
“签名角色”恰好是这种表现forms的完美之选。
二进制数据OTOH只是取每个8位“数据块”的值,因此不需要任何符号。
字节算术对计算机图形很重要(其中8位值通常用于存储颜色)。 除此之外,我可以想到两个主要的情况,其中char标志很重要:
- 转换为更大的int
- 比较function
令人讨厌的是,如果你的所有字符串数据都是7位,这些都不会咬你。 但是,如果你想让你的C / C ++程序保持干净,那么它有望成为一个无法解决的错误来源。
签名在char
的工作方式与在其他整数类型中的工作方式大致相同。 正如您所指出的,字符实际上只是一个字节的整数。 ( 不一定是8位 !有区别;在某些平台上,一个字节可能大于8位,由于char
和sizeof(char)
的定义, char
更依赖于字节。定义了CHAR_BIT
宏在
或C ++的
,将告诉你char
中有多少位。)。
至于为什么你想要一个带符号的字符:在C和C ++中,没有称为byte
标准类型。 对于编译器, char
是字节,反之亦然,并且它们不区分它们。 但是,有时您希望 – 有时您希望该char
是一个单字节的数字,在这种情况下(特别是一个字节可以有多小的范围),您通常也会关心该数字是否有符号。 我个人使用签名(或无符号)来表示某个char
是(数字)“字节”而不是字符,并且它将以数字方式使用。 没有指定的签名,该char
实际上是一个字符,并且旨在用作文本。
我过去常常这样做。 现在,较新版本的C和C ++有(u?)int_least8_t
(当前在
或
是typedef),它们更明确地是数字的(尽管它们通常只是有符号和无符号char
typedef)类型无论如何)。
我可以想象这是一个问题的唯一情况是你选择在字符上做数学。 编写以下代码是完全合法的。
char a = (char)42; char b = (char)120; char c = a + b;
根据char的签名,c可以是两个值之一。 如果char是无符号的,那么c将是(char)162。 如果它们被签名则会出现溢出情况,因为签名字符的最大值为128.我猜大多数实现只返回(char)-32。
关于签名字符的一件事是你可以测试c> =”(空格)并确保它是一个普通的可打印ascii字符。 当然,它不便携,所以不是很有用。