在C语言中,unsigned int和signed int有什么区别?

42

考虑以下定义:

int x=5;
int y=-5;
unsigned int z=5;

它们在内存中是如何存储的?有人可以解释一下它们在内存中的位表示吗?

int x=5int y=-5在内存中是否可以具有相同的位表示?


最好的解释 链接 - Dhiren Hamal
5个回答

51

ISO C规定了它们之间的区别。

int数据类型是有符号的,其最小范围至少为-32767到32767(包括)。实际值在limits.h中分别给出为INT_MININT_MAX

unsigned int具有0到65535(含)的最小范围,实际最大值来自同一头文件的UINT_MAX

除此之外,标准并不强制要求采用二进制补码表示编码值,这只是其中的一种可能性。对于使用16位数据类型的5和-5,三种允许的类型将具有以下编码:

        two's complement  |  ones' complement   |   sign/magnitude
    +---------------------+---------------------+---------------------+
 5  | 0000 0000 0000 0101 | 0000 0000 0000 0101 | 0000 0000 0000 0101 |
-5  | 1111 1111 1111 1011 | 1111 1111 1111 1010 | 1000 0000 0000 0101 |
    +---------------------+---------------------+---------------------+
  • 在二进制补码中,将一个数的所有位取反再加1可得到它的相反数。
  • 在一的补码中,将一个数的所有位取反即可得到它的相反数。
  • 在符号-大小表示法中,最高位为符号位,因此只需取反该位即可得到相反数。

请注意,对于所有表示法,正数的编码都相同,只有负数的编码不同。

此外,对于无符号数,您不需要使用其中的一位来表示符号。这意味着您可以获得更多的正数范围(当然,代价是没有负数的编码)。

还要注意的是,不管使用哪种表示法,“5”和“-5”不能具有相同的编码,否则就无法区分它们了。


另外,目前在C和C++标准中正在进行行动,以将二进制补码作为负整数的唯一编码。


5
它确实规定了要选择二进制补码、反码或原码中的一种,但不改变其含义。 - caf
符合规范的实现是否可以使用相同的表示方法来处理有符号和无符号数,并仅强制在声明为“无符号”的类型的操作中将符号位设置为'0'(使其实质上成为一个“填充位”)? - supercat
1
可能,我认为这可能是允许的,但由于最小范围为0-65536,您需要至少17位来实现该方案。这将排除16位无符号整数,但对于32位整数可能还可以。我不确定这一点,因为我还没有仔细研究ISO是否规定了无符号包装,但至少对于当前的CPU来说,这似乎是低效/浪费的。 - paxdiablo
二进制补码是一种非常优雅的系统。它不仅易于在硬件中实现,还允许您使用现有的加法硬件来执行减法——将二进制补码数字添加到无符号整数上执行减法。 - Spatial
你好。我之前只知道符号/大小编码,并且在关于Java的文章中假定它保留符号 https://www.javamex.com/java_equivalents/unsigned.shtml ... 那么除了C语言,其他语言是否也有使用这种三变量自由的编码方式? - Valter Ekholm

5

因为一切都是关于内存的,最终所有的数值都以二进制形式存储。

一个32位无符号整数可以包含从二进制0到二进制1的所有值。

当涉及到32位有符号整数时,它意味着其中一位(最高位)是一个标志,标记该值是正数还是负数。


您能告诉我在这种情况下如何检查给s8(8位有符号)的值是否超出范围吗?我应该将该值与0x7F进行比较,而不是0xFF吗?并且我应该先检查符号位吗?谢谢。 - The Beast

4

C标准指定无符号数将以二进制形式存储(带有可选的填充位)。有三种格式可以存储有符号数:大小和符号;二进制补码或一的补码。有趣的是,这排除了某些其他表示法,如Excess-n或Base-2

然而,在大多数机器和编译器上,有符号数以二进制补码形式存储。

int通常为16或32位。标准规定int应该是底层处理器最有效的类型,只要它>= short<= long,就符合标准。

在某些机器和操作系统上,历史原因导致int不是当前硬件的最佳大小。


好的,在16位编译器上,你能告诉我int x=5和int y=-5在内存中是如何存储的吗?请提供位表示。 - Anand Kumar
很抱歉,你的答案是错误的。 C语言非常明确地规定了整数的表示方式。特别是对于无符号类型,编译器实现的选择余地不多。但即使对于有符号类型,标准也相当严格。而且“int”并不是处理器效率最高的类型。在大多数情况下,它现在卡在32位(仅仅是为了语法上的原因),而64位通常是最有效的。 - Jens Gustedt
我猜在三进制存储器的机器上无法使用标准C语言? - Douglas Leeder
@Douglas:太好了,异议已解除。 - Jens Gustedt
我想,如果没有二进制整数,位运算符就没有多大意义了。 - Douglas Leeder
显示剩余5条评论

3
这是一个很好的链接,解释了C语言中有符号和无符号整数的存储方式 -

http://answers.yahoo.com/question/index?qid=20090516032239AAzcX1O

从上面的文章中得知-

“使用称为二进制补码的过程将正数转换为负数。这样做的副作用是最高有效位用于告诉计算机数字是正数还是负数。如果最高有效位为1,则数字为负数。如果为0,则数字为正数。”


好的,关于16位编译器,你能告诉我int x=5和int y=-5在内存中是如何存储的吗?请提供位表示。 - Anand Kumar
6
请注意,2的补码并不是C实现中允许的唯一有符号表示法——反码和补码也同样被允许。 - caf

0
假设int是一个16位整数(这取决于C实现,大多数现在是32位),其位表示如下:
 5 = 0000000000000101
-5 = 1111111111111011

如果将二进制数1111111111111011设置为无符号整数,则它将是十进制数65531。

6
顺便说一下,ISO C标准不强制要求使用二进制补码表示法。 - paxdiablo
16位编译器上可以吗?你能告诉我int x=5和int y=-5在内存中是如何存储的吗?请提供位表示。 - Anand Kumar
@Anand:你真正想要什么?答案中已经有二进制补码的位表示了。 - Jens Gustedt
嗨,我想问一下,如果我写signed int x=5;,它会以2的补码形式存储值吗?如果我写signed int x=-5;,它会以2的补码形式存储值吗? - Anand Kumar
“int x = 5” 在二进制补码、一的补码和反码下存储方式相同。在大多数常见的实现中,“int x = -5” 存储为二进制补码,但不要依赖这种方式编写可移植代码。 - Bill Evans at Mariposa

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