在C编程中,为什么char a = -1与unsigned char b = -1不同

时间:2013-01-09 12:25:28

标签: c

我在下面写了一个小程序。

#include <stdio.h>
main(){
    char a=-1;
    unsigned char b=-1;
    printf("%d %d\n",a,b);
    printf("%x %x\n",a,b);
    if(a==b) printf("equal\n");
    else printf("not equal\n");
}

编程的输出是:

-1 255
ffffffff ff
not equal

因为char只有一个字节而-1用2的补码形式表示,我认为0xff将存储在a&amp; b因此两者应该是平等的。任何人都可以让我知道为什么他们是不同的,为什么十六进制的一个是0xffffffff&amp;不是0xff。我有一个相关的链接http://embeddedgurus.com/stack-overflow/2009/08/a-tutorial-on-signed-and-unsigned-integers/,但我无法得到答案。任何帮助将不胜感激。感谢。

4 个答案:

答案 0 :(得分:5)

他们是一样的。或者更确切地说,它们的底层表示是相同的(假设您的编译器使用双补码形式)。

另一方面,它们代表的值是-1和255。

当您打印它们时,它们扩展到数据类型intunsigned char为零扩展,而签名字符是符号扩展,这可以解释您看到的差异。

比较两个值时会发生相同的扩展。 a == b不比较底层表示,而是将两个值都扩展为int,因此它将255与-1进行比较,这是不相等的。

请注意,普通char可以是签名的也可以是未签名的。在您的环境中,它显然是签名的。

答案 1 :(得分:2)

char类型有点异常,因为它与signed charunsigned char不同(与其他整数类型不同 - short,{{ 1}},int等 - 除非明确声明long,否则将被隐式签名。 unsigned是否实际签名是依赖于实现的,有些编译器甚至允许您通过命令行开关指定签名。

底线:永远不要假设char已签名或未签名 - 如果您确实需要有符号或无符号8位数量,请明确使用charsigned char,或者更好地使用来自unsigned char的{​​{1}}或int8_t

答案 2 :(得分:2)

signed int已签名,unsigned int未签名。如果仅使用int,则表示signed intshortlonglong long也是如此。但char并非如此。 signed char已签名,unsigned char未签名,但只有char可以是已签名或未签名。数据类型char应该包含“字符”,因此名称,因此它不是“真正”整数类型来保存要在计算中使用的整数。当然,角色实际上是某种类型的整数但是依赖于实现的类型(C标准不强制任何特定种类)。因此,如果您希望将char类型用于整数值(也用于计算),请始终明确使用signed charunsigned char,并在实际处理字符时仅使用char或如果char签名或未签名,它对你的代码完全没有区别。

比较失败,因为您的实现将char定义为signed char,因此您要将signed charunsigned char中的if进行比较if((int)a==(int)b) printf("equal\n"); else printf("not equal\n"); } 声明。每当您比较两个不同类型的整数时,编译器在实际执行比较之前将两个值都转换为相同的类型according to the rules of the C standard。在您的情况下,这意味着C编译器实际执行以下操作:

(int)a

现在很明显为什么这两个值不匹配。 -1的值为(int)b,但255的值为char,且这两个值不相等。

根据类型促销的规则,int(在您签名的情况下)被提升为unsigned charint也被提升为{{1} }}。 ISO C 2011标准说:

  

如果int可以表示原始类型的所有值(限制为   通过宽度,对于位字段),该值被转换为int;   否则,它将转换为unsigned int。这些被称为   整数提升。)所有其他类型的整数不变   促销。

     

整数促销保留包括符号在内的值。如上所述   之前,“普通”字符是否被视为已签名   实现定义的。

答案 3 :(得分:0)

虽然围绕一个普通的“char”(见Is char signed or unsigned by default?)存在一些模糊性,但这并不是我认为的唯一的事情。

文字-1是一个整数,它不会(sizeof(int)&gt; sizeof(char),为了参数)“适合”到char。双补码位模式0xffff(32位int为在这里截断并复制参数缘故。

当你调用printf()时,参数被提升为整数类型,有符号类型是“符号扩展”,但是无符号“b”不是,并且填充为零。当您对两个不同类型使用“==”时,会执行类似(但不一定相同)的类型转换(也就是“通常的算术转换”)。

另请参阅Default argument promotions in C function callsSigned and unsigned, and how bit extension works in C