简体   繁体   English

为什么在C编程中char a = -1与无符号char b = -1不同

[英]why char a=-1 is different from unsigned char b=-1, in C programming

i have written a small program below. 我在下面写了一个小程序。

#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");
}

The output of the prog is : 该编的输出为:

-1 255
ffffffff ff
not equal

since char is only one byte and -1 is represented in 2's complement form, i thought that 0xff will be stored in both a & b and hence both should be equal. 由于char仅为一个字节,并且-1以2的补码形式表示,我认为0xff将同时存储在a和b中,因此两者应相等。 Can anyone let me know why they are different and why hex rep'n of a is 0xffffffff & not 0xff. 谁能告诉我为什么它们不同以及为什么a的十六进制表示是0xffffffff而不是0xff。 i got a related link http://embeddedgurus.com/stack-overflow/2009/08/a-tutorial-on-signed-and-unsigned-integers/ but i couldn't get the answer. 我有一个相关的链接http://embeddedgurus.com/stack-overflow/2009/08/a-tutorial-on-signed-and-unsigned-integers/,但我找不到答案。 any help will be greatly appreciated. 任何帮助将不胜感激。 thanks. 谢谢。

They are the same. 他们是一样的。 Or rather, their underlying representation is the same (under the assumption that your compiler use two-complement form). 或者,它们的基本表示形式是相同的(假设您的编译器使用两个补码形式)。

On the other hand, the values they represent are -1 and 255. 另一方面,它们表示的值为-1和255。

When you print them, they are extended to the data type int . 当您打印它们时,它们将扩展int数据类型。 unsigned char is zero-extended whereas a signed char is sign extended, which accounts for the differences you see. unsigned char是零扩展的,而signed char是符号扩展的,这说明了您看到的差异。

The same extension occurs when you compare the two values. 比较两个值时,会发生相同的扩展名。 a == b don't compare the underlying representations, instead, it extends both values to int so it compares 255 with -1, which isn't equal. a == b不比较基础表示,而是将两个值都扩展为int因此将255与-1比较,这是不相等的。

Note that a plain char may be either signed or unsigned. 请注意,普通char可以是有符号的也可以是无符号的。 In your environment, it is obviously signed. 在您的环境中,显然已签名。

The char type is something of an anomaly in that it is not the same as either signed char or unsigned char (unlike the other integer types - short , int , long , etc - which are implicitly signed unless explicitly declared unsigned ). char类型是一种异常,因为它与有signed charunsigned char不同(不同于其他整数类型shortintlong等-除非明确声明为unsigned否则它们是隐式unsigned )。 Whether char is actually signed or not is implementation-dependent, and some compilers even let you specify the signedness via a command line switch. char是否实际签名取决于实现,并且某些编译器甚至允许您通过命令行开关指定签名。

Bottom line: never assume that char is signed or unsigned - if you actually require a signed or unsigned 8 bit quantity then use signed char or unsigned char explicitly, or better still, use int8_t or uint8_t from <stdint.h> . 底线:永远不要假设char是带符号的或无符号的-如果您实际上需要带符号的或无符号的8位数字,则显式使用带signed charunsigned char ,或者更好的是,使用<stdint.h> int8_tuint8_t

A signed int is signed, an unsigned int is unsigned. 一个signed int签订后,一个unsigned int是无符号。 If you use just int , it implies signed int . 如果仅使用int ,则表示signed int Same is true for short , long or long long . shortlonglong long也是如此。 Yet it isn't true for char . 但是,对于char并非如此。 A signed char is signed, an unsigned char is unsigned, but just char may be either signed or unsigned. 一个signed char是签名的,一个unsigned char是未签名的,但是只有char可以是签名的也可以是未签名的。 The data type char is supposed to hold a "character", hence the name, so it's not "really" an integer type to hold an integer number to be used in calculations. 数据类型char应该包含一个“字符”,也就是这个名称,因此它不是“真正”一个整数类型来保存要在计算中使用的整数。 Of course a character is in reality an integer of some kind but of which kind is implementation dependent (the C standard does not force any specific kind). 当然,字符实际上是某种整数,但是哪种类型取决于实现(C标准不强制使用任何特定的类型)。 So if you want to use the char type for integer values (also used in calculations), always use signed char or unsigned char explicitly and only use just char when you are really dealing with characters or when it makes absolutely no difference for your code if char is signed or unsigned. 因此,如果要将char类型用于整数值(也在计算中使用),请始终明确使用有signed charunsigned char并且仅在真正处理字符或对代码绝对没有区别时才使用char字符已签名或未签名。

The comparison fails because your implementation defines char to be in fact signed char , so you are comparing a signed char to an unsigned char in your final if statement. 因为你实现定义比较失败char是其实signed char ,让您比较一个signed char到一个unsigned char在最终if语句。 Whenever you are comparing two integers of different type, the compiler converts both values to the same type according to the rules of the C standard before it actually performs the comparison. 每当您比较两个不同类型的整数时,编译器都会在实际执行比较之前根据C标准的规则将两个值转换为相同类型。 In your case, this means the C compiler actually does tho following: 在您的情况下,这意味着C编译器实际上会执行以下操作:

if((int)a==(int)b) printf("equal\n");
    else printf("not equal\n");
}

And now it should be obvious why those two values don't match. 现在很明显,为什么这两个值不匹配。 (int)a has a value of -1 , however (int)b has a value of 255 , and these two values are not equal. (int)a的值为-1 ,但是(int)b的值为255 ,并且这两个值不相等。

According to the rules of type promotion , char (in your case signed) is promoted to int and unsigned char is also promoted to int . 根据类型提升的规则, char (在您的情况下为signed)将提升为intunsigned char也将提升为int The ISO C 2011 standard says: ISO C 2011标准说:

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; 如果一个int可以表示原始类型的所有值(受位字段的宽度限制),则该值将转换为int; otherwise, it is converted to an unsigned int. 否则,它将转换为unsigned int。 These are called the integer promotions.) All other types are unchanged by the integer promotions. 这些称为整数促销。)所有其他类型均不受整数促销的影响。

The integer promotions preserve value including sign. 整数促销保留包括符号在内的价值。 As discussed earlier, whether a ''plain'' char is treated as signed is implementation-defined. 如前所述,是否将“普通”字符视为已签名是实现定义的。

While there is some ambiguity around a plain "char" (see Is char signed or unsigned by default? ) that's not the only thing that's going on here I think. 尽管在普通的“字符”周围存在一些歧义(请参见默认情况下,字符是有符号的还是无符号的? ),但我认为这并不是唯一的事情。

A literal -1 is an integer, it won't (sizeof(int)>sizeof(char), for arguments sake) "fit" into a char.The two-complement bit pattern 0xffff (32 bit int for arguments sake) is truncated and copied here. 文字-1是整数,不会(为了参数而将sizeof(int)> sizeof(char))“适合”到char中。两个补码的位模式0xffff(为参数而为32位int)为被截断并复制到此处。

When you call printf() the parameters are promoted to integer type, a signed type is "sign-extended", but the unsigned "b" is not, and zero padded. 当您调用printf()时,参数将提升为整数类型,带符号类型为“符号扩展”,但不带符号的“ b”则为零,且填充为零。 When you use "==" with two distinct types a similar (but not necessarily identical) type conversion is performed (aka the "usual arithmetic conversions"). 当您将“ ==”与两个不同的类型一起使用时,将执行类似(但不一定相同)的类型转换(也称为“通常的算术转换”)。

See also Default argument promotions in C function calls and Signed and unsigned, and how bit extension works in C . 另请参见C函数调用Signed和Unsigned中的 默认参数提升 ,以及C中的位扩展如何工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM