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

时间:2009-01-16 18:01:30

标签: c string character-encoding char signed

鉴于有符号和无符号整数使用相同的寄存器等,并且只是不同地解释位模式,C字符基本上只是8位整数,C中有符号和无符号字符之间的区别是什么?我理解char的签名是实现定义的,我根本无法理解它是如何产生影响的,至少当char用于保存字符串而不是数学时。

9 个答案:

答案 0 :(得分:22)

字符串不会有所作为。但是在C语言中你可以使用char来进行数学运算,这会产生影响。

事实上,当在受限制的内存环境中工作时,如嵌入式8位应用程序,通常会使用char来进行数学运算,然后它会产生很大的不同。这是因为C中默认没有byte类型。

答案 1 :(得分:19)

就他们所代表的价值而言:

unsigned char:

  • 跨越值范围0..255 (00000000..11111111)
  • 值在低边缘溢出:

    0 - 1 = 255 (00000000 - 00000001 = 11111111)

  • 值在高边缘溢出:

    255 + 1 = 0 (11111111 + 00000001 = 00000000)

  • 按位右移运算符(>>)执行逻辑移位:

    10000000 >> 1 = 01000000 (128 / 2 = 64)

签名char:

  • 跨越值范围-128..127 (10000000..01111111)
  • 值在低边缘溢出:

    -128 - 1 = 127 (10000000 - 00000001 = 01111111)

  • 值在高边缘溢出:

    127 + 1 = -128 (01111111 + 00000001 = 10000000)

  • 按位右移运算符(>>)执行算术移位:

    10000000 >> 1 = 11000000 (-128 / 2 = -64)

我包含了二进制表示,以表明值包装行为是纯粹的,一致的二进制算术,与被签名/无符号的char无关(期望右移)。

<强>更新

评论中提到的一些特定于实现的行为:

答案 2 :(得分:10)

#include <stdio.h>

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

排序字符串时很重要。

答案 3 :(得分:3)

有一些区别。最重要的是,如果通过为char分配一个太大或小的整数来溢出char的有效范围,并且char被签名,则结果值是实现定义的,或者甚至某些信号(在C中)可能会升高,就像所有签名类型一样。与你为无符号字符分配太大或太小的东西的情况形成对比:值环绕,你将获得精确定义的语义。例如,将-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 ++中,所有三种字符类型都没有填充位。

答案 4 :(得分:2)

  
    

“签名的字符是什么意思?”

  

传统上,ASCII字符集由7位字符编码组成。 (与8位EBCIDIC相反。)

当C语言被设计和实现时,这是一个重要问题。 (由于各种原因,例如通过串行调制解调器设备进行数据传输。)额外位具有奇偶校验等用途。

“签名角色”恰好适合这种表现形式。

二进制数据OTOH只是取每个8位“数据块”的值,因此不需要任何符号。

答案 5 :(得分:1)

字节算术对计算机图形很重要(其中8位值通常用于存储颜色)。除此之外,我可以想到两个主要的情况,其中char标志很重要:

  • 转换为更大的int
  • 比较功能

令人讨厌的是,如果你的所有字符串数据都是7位的话,这些都不会咬你。但是,如果你想让你的C / C ++程序保持干净,那么它有望成为一个无法解决的错误来源。

答案 6 :(得分:1)

签名在char中的工作方式与在其他整数类型中的工作方式大致相同。正如您所指出的,字符实际上只是一个字节的整数。 (不一定是8位!有区别;某些平台上的字节可能大于8位,char由于{的定义而与字节相关联{1}}和char。在sizeof(char)或C ++的CHAR_BIT中定义的<limits.h>宏将告诉您<climits>中有多少位。)

至于为什么你想要一个带符号的角色:在C和C ++中,没有一种叫做char的标准类型。对于编译器,byte是字节,反之亦然,并且它们不区分它们。但是,有时您希望 - 有时您希望 char是一个单字节的数字,在这种情况下(特别是一个字节可以有多小的范围),通常也会关心号码是否已签名。我个人使用签名(或无符号)来表示某个char是一个(数字)“字节”而不是一个字符,并且它将在数字上使用。没有指定的签名,char确实是一个字符,并且打算用作文本。

我过去常常这样做。现在,较新版本的C和C ++有char(当前在(u?)int_least8_t<stdint.h>中的typedef),它们更明确地是数字的(尽管它们通常只是用于签名的typedef)无论如何都是无符号的<cstdint>类型。)

答案 7 :(得分:0)

我能想象这是一个问题的唯一情况是你选择在字符上做数学。编写以下代码是完全合法的。

char a = (char)42;
char b = (char)120;
char c = a + b;

根据char的签名,c可以是两个值之一。如果char是无符号的,那么c将是(char)162。如果它们被签名则会出现溢出情况,因为签名字符的最大值为128.我猜大多数实现只返回(char)-32。

答案 8 :(得分:0)

签名字符的一个方面是你可以测试c&gt; =''(空格)并确保它是一个普通的可打印的ascii字符。当然,它不便携,所以不太有用。