如何确定变量是已签名还是未取消
在C程序中,如果整数是有signed integer
,则最高位为1
,否则为0
。
让我们使用char
和unsigned char
, signed char
的范围是-128
到127
, unsigned char
是0
到255
,但实际上它们的hex在0x00
到0xff
范围内。 我现在的问题是,如果使用8位二进制数将char
和unsigned char
存储在内存中,计算机本身如何知道它是已signed
还是unsigned
?
char a = 0xff; printf("%d", a); //its result is -1. unsigned char a = 0xff; printf("%d", a); //its result is 255.
在上面的例子中, printf
如何知道0xff
的值是有符号还是无符号? 这只取决于a
?的定义?
这里有许多相关的问题,例如这个问题。
你的问题不太正确:对于signed
,最高位并不总是1
– 只有当值为负时。 实际上,有signed
或unsigned
是归因于完全相同的位模式的“类型”,并且在比较或提升时如何解释这些位模式由它们各自的类型定义。
例如:
unsigned char u = 0xFF; // decimal 255 signed char s = 0xFF; // decimal -1
您可以在设置的最高位中看到两个值是如何相同的,但它们的类型不同。
编译器使用类型系统来了解如何解释值,程序员的任务是为值分配有意义的类型。 在上面的例子中,我告诉编译器第一个0xFF
应该被解释为unsigned
值(参见include文件limits.h ),其最大范围是:
u = 0x00; // decimal 0, CHAR_MIN u = 0xFF; // decimal 255, UCHAR_MAX
第二个0xFF
作为带有最大范围的有signed
值:
s = 0x00; // decimal 0, CHAR_MIN s = 0x7F; // decimal 127, SCHAR_MAX s = 0x80; // decimal -127, SCHAR_MIN (note how 0x7F + 1 = 0x80, decimal 127 + 1 = -127, called an overflow) s = 0xFF; // decimal -1
对于示例中的printf, %d
告诉它期望有signed int
值。 根据C语言的整数提升规则,较小的char
类型是符号扩展(如果是有signed
类型)或零扩展(如果它是unsigned
类型)。 完成上面的例子:
printf("%d", u); // passes a int 0x000000FF, decimal 128, to the function printf("%d", s); // passes a int 0xFFFFFFFF, decimal -1, to the function
这里有更多printf格式说明符,例如%u
在这种情况下可能对你有意义。
在printf()
调用(和其他场合)上,适用整数提升规则。
编译器将给定值转换为int
。 这取决于char的签名(当然,编译器已知)。 因此,根据char的签名,编译器通过填充0
位或char的最高位来完成转换。
在C程序中,如果整数是有符号整数,则最高位为1,否则为0。
这个说法不正确。
在C程序中,如果整数是负有符号整数,则最高位为1,否则为0。
这个陈述也是不正确的。
在使用二进制补码有符号整数的C程序中,如果整数是负有符号整数,则最高位为1,否则为0。
那是对的。
让我们使用char和unsigned char,signed char的范围是-128到127,unsigned char是0到255,但实际上它们的hex在0x00到0xff的范围内。
这种说法令人困惑和误导。 0xFF
只是编写128的另一种方式。你也可以说“在hex中,有符号字符的范围是-0x80
到0x7F
,而有符号字符的范围是0x00
到0xFF
。”
我现在的问题是,如果使用8位二进制数将char和unsigned char存储在内存中,计算机本身如何知道它是已签名还是未签名?
电脑不知道。 您可以通过键入unsigned
一词来告诉它是否要将该内存解释为带符号数或无符号数。
在上面的例子中,printf如何知道0xff的值是有符号还是无符号?
将printf
删除。 让我们举一个更简单的例子:
char a = 128;
怎么了? 128大于最大可能的有符号字符(再次假设二进制补码中有8位字符)。 因此,值包含在尽可能小的值 ; 这变成-128。
char a = 129;
怎么了? 129比最大可能的签名字符大2 。 所以它包围了第二个可能的最小值 -127。
char a = 130;
这比最大可能值大3,因此它包含到第三个可能的最小值 -126。
….跳过几个……
char a = 255;
这比最大可能值大128,因此它包围到第128个最小可能值,即-1。
得到它了?
好了,现在我们明白了:
char a = 255; unsigned char b = 255;
现在,当我们说时会发生什么
int c = a; int d = b;
? 我们有一个有符号整数。 我们已经确定已经回绕到-1,它在整数范围内,因此c
变为整数-1。 b
是无符号字符255,它在整数范围内,因此d
变为整数255
。
a
和b
的内存内容相同的事实是无关紧要的。 该内存被解释为基于您分配给a
和b
的类型 的数字 。 特别是,该位模式到整数位模式的转换完全取决于类型。