如何确定一个变量是有符号还是无符号?

6
在使用2的补码整数的C语言实现中,如果一个有符号整数是负数,则最高位为1,否则为0。对于charunsigned charsigned char的范围是-128127,而unsigned char的范围是0255,但实际上它们的十六进制范围是0x000xff。现在我的问题是,如果在内存中使用8位二进制数存储charunsigned 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 的定义吗?

3
顺便说一下,C语言不区分 0xff0377255 - Brave Sir Robin
3个回答

7

这里有很多相关的问题,比如this

你的问题不太正确:对于signed,最高位并不总是1——只有当值为负数时才是。实际上,signedunsigned都是被赋予了相同的位模式的“类型”,它们在比较或提升时如何解释这些位模式是由它们各自的类型定义的。

例如:

unsigned char u = 0xFF; // decimal 255
signed char s = 0xFF; // decimal -1

你可以看到两个数值都是相同的,都设置了最高位,但它们的类型不同。
编译器使用 类型系统 来知道如何解释数值,程序员的任务是为数值分配有意义的类型。在上面的例子中,我告诉编译器第一个 0xFF 应该被解释为 unsigned 值(也可以查看包含文件 limits.h ),并且具有最大范围:
u = 0x00; // decimal 0, CHAR_MIN
u = 0xFF; // decimal 255, UCHAR_MAX

将第二个0xFF作为最大范围内的有符号值进行转换:

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告诉它期望一个有符号整数值。根据C语言的整数提升规则,较小的char类型是通过符号扩展(如果它是有符号类型)或零扩展(如果它是无符号类型)来处理的。完成以上示例:
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在这种情况下可能对您很有趣。

6
printf()调用(和其他情况下),整数提升规则适用。编译器将给定的值转换为int。这取决于char的有符号性(当然,编译器知道)。因此,根据char的有符号性,编译器通过填充0位或char的最高位来进行转换。

3
让我们以字符和无符号字符为例,有符号字符的范围是-128到127,无符号字符的范围是0到255,但实际上它们的十六进制范围是0x00到0xff。
这种说法令人困惑且误导。 0xFF只是表示255的另一种方式。 您可以这样说:“用十六进制表示,有符号字符的范围是-0x800x7F,无符号字符的范围是0x000xFF。”
现在我的问题是,如果char和unsigned char使用8位二进制数存储在内存中,计算机如何知道它是有符号还是无符号?
计算机并不知道。通过输入单词unsigned来告诉它你要将该内存解释为有符号数字或无符号数字。
在上面的例子中,printf如何知道0xff的值是有符号还是无符号的?
printf放在一边。让我们举一个简单的例子:
char a = 128; 

发生了什么?128比有符号字符的最大可能值要大(假设采用二进制补码表示8位字符)。 因此,这个值“环绕回到最小可能值”;它变成了-128。
char a = 129;

发生了什么?129比有符号字符的最大值大两个。因此它会绕回到第二个最小可能值,即-127。

char a = 130;

这个数比最大可能值大,所以它会绕回到第三个最小可能值-126。

.... 跳过一些 ...

char a = 255;

这个数比最大可能的值大128,所以它会绕回到第128个最小可能的值,即-1。

明白了吗?

好的,现在我们理解了:

char a = 255;
unsigned char b = 255;

现在,当我们说

int c = a;
int d = b;

? 我们有一个带符号整数 a,我们已经确定它已经绕到了-1,这是一个整数范围内的数字,因此c变成了整数-1。 b 是无符号字符255,这也在整数范围内,所以d变成了整数255

ab在内存中的内容相同这一事实是不相关的。该内存根据您分配给ab类型被解释为数字。特别地,将该位模式转换为整数位模式完全取决于类型。


"0xFF只是另一种表示128的方式而已。" 重新写法可以如下: "0xFF是用来表示128的另一种方式。" - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接