签署一个字符是什么意思?

鉴于有符号和无符号整数使用相同的寄存器等,并且只是不同地解释位模式,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位,由于charsizeof(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字符。 当然,它不便携,所以不是很有用。