有符号整数与无符号整数

445

我正确地说无符号整数和有符号整数之间的区别是:

  1. 无符号整数可以容纳更大的正值,但不能存储负值。
  2. 无符号整数使用最高位作为值的一部分,而有符号版本使用最高位来标识数字的正负性。
  3. 有符号整数可以容纳正数和负数。

还有其他区别吗?


14
因为0既不是正数也不是负数,因此用术语“非负值”比用“正值”更加合适来表示无符号整数。 - Daniel
17个回答

382

无符号整数可以存储比有符号整数更大的正值,但不包括负数。

是的。

无符号整数使用最高位作为值的一部分,而有符号版本使用最左边的位来识别数字是正还是负。

表示有符号整数的方法有不同的方式。最容易想象的是使用最左边的位作为标志(符号加绝对值),但更常见的是使用二进制补码。这两种表示方法都在大多数现代微处理器中使用——浮点数使用符号加绝对值,而整数运算使用二进制补码。

有符号整数可以存储正数和负数。

是的。


102

我将讨论x86硬件层面的差异,这主要与编写编译器或使用汇编语言相关,但了解此知识还是很好的。

首先,x86原生支持有符号数的 二进制补码 表示。您可以使用其他表示方式,但这会需要更多指令,并且通常会浪费处理器时间。

什么叫做“原生支持”?基本上,这意味着存在一组用于无符号数的指令和一组用于有符号数的指令。无符号数可以存储在与有符号数相同的寄存器中,实际上,您可以混合使用有符号和无符号指令而不必担心处理器。编译器(或汇编程序员)需要跟踪一个数字是否为有符号,并使用适当的指令。

首先,二进制补码具有加法和减法性质,与无符号数完全相同。这使得该数字是正数还是负数没有任何影响。(因此,您只需毫无顾虑地执行ADDSUB操作即可。)

当涉及比较时,差异开始显现:x86有一种简单的方法来区分它们:above/below表示无符号比较,greater/less than 表示有符号比较。(例如,JAE 表示“跳转到以上或等于”,是无符号的)

还有两组乘法和除法指令来处理有符号整数和无符号整数。

最后:如果您想检查溢出,例如检查有符号数和无符号数,那么需要使用不同的方法。


88

他只问了有符号和无符号的问题,不知道为什么有人要添加额外的内容。让我告诉你答案。

  1. 无符号:它仅包含非负值,即0到255。

  2. 有符号:它包含正数和负数,但格式不同,如下:

    • 0到+127
    • -1到-128

这个解释是关于8位数字系统的。


2
不错。简单明了。精彩的工作。 - chaotic3quilibrium

20
根据我们在课堂上学到的知识,带符号整数可以表示正数和负数,而无符号整数仅可以表示非负数。
例如,观察一个8位数字:
- 无符号值为0到255 - 带符号值范围从-128到127

18

为了完整起见,以下是一些要点:

  • 本答案仅讨论整数表示法。对于浮点数可能有其他答案;

  • 负数的表示可以有所不同。目前使用最广泛(几乎普遍)的是二进制补码。其他表示法包括原码反码(相当罕见)和带符号数值(非常罕见 - 可能只在博物馆里使用),后者只是使用高位作为符号指示符,其余位表示数值的绝对值。

  • 当使用二进制补码时,变量可以表示比正数更大的负数范围(加上一个)。这是因为零被包括在“正数”中(因为零的符号位未设置),而不是负数。这意味着最小负数的绝对值无法表示。

  • 当使用原码反码或带符号数值时,零可以被表示为正数或负数(这是这些表示法通常不使用的原因之一)。


如果我写 unsigned int a = -2,和 signed int b = -2,底层表示会相同吗?我知道给无符号数一个负值不好,但是如果我这样做了,底层表示会是什么? - Suraj Jain
1
小问题:在IEEE浮点数中使用了符号和大小,因此它实际上非常常见。 :-) - al45tair

11

除了第二点之外,其余都是正确的。有许多不同的有符号整数表示法,一些实现使用第一个,另一些使用最后一个,还有些则完全使用不同的表示法。这完全取决于你所使用的平台。


那是指小端和大端的问题吗? - vIceBerg
小端和大端与平台上字节的顺序有关。小端可能会执行0xFF 0xFE 0x7F,而大端会执行0x7F 0xFE 0xFF。 - Jasper Bekkers

10

另一个区别是当你在不同大小的整数之间进行转换时。

例如,如果你从字节流中提取一个整数(假设简单起见为16位),使用无符号值,你可以这样做:

i = ((int) b[j]) << 8 | b[j+1]

(也许应该将第二个字节转换为特定类型,但我猜编译器会做正确的事情)

对于带符号值,您需要担心符号扩展并进行以下操作:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF

7

除了其他人说的之外,在C语言中,您无法溢出无符号整数;其行为被定义为模算术。您可以溢出有符号整数,并且理论上(尽管在当前主流系统上实践中不会发生),溢出可能会触发故障(可能类似于除以零故障)。


3
请注意,有符号整数溢出会触发未定义行为,并且现代编译器非常激进地发现并利用它以意想不到但在技术上合法的方式修改您的程序,因为它们可以假设未定义的行为不会发生 - 粗略地说。这比7年前更成问题。 - Jonathan Leffler

6
在C语言中,有符号整数代表数字。如果ab是有符号整数类型的变量,则标准永远不会要求编译器将表达式a += b储存到a中除了它们各自值的算术和之外的任何其他内容。确保如果算术和无法适合a,则处理器可能无法将其放置在那里,但是标准不会要求编译器截断或包装值,或者对于超过类型限制的值执行任何其他操作。请注意,尽管标准不要求,但C实现允许使用带符号值捕获算术溢出。
在C中,无符号整数的行为类似于模某个二的幂次的抽象代数整数环,除了涉及转换或与较大类型操作的情况。将任何大小的整数转换为32位无符号类型将产生对应于模4,294,967,296等于该整数的元素。从2中减去3得到4,294,967,295的原因是将与3同余的值加上与4,294,967,295同余的值将得到与2同余的值。
抽象代数整数环类型通常很方便;不幸的是,C使用有符号性作为类型应该如何行为的决定因素。更糟糕的是,当转换为较大类型或对小于int的无符号值执行任何算术运算时,无符号值被视为数字而不是环成员。如果v是等于4,294,967,294uint32_t,则v *= v;应该使v = 4。不幸的是,如果int是64位,则无法确定v *= v;会做什么。
考虑到现有标准,建议在需要代数环相关行为的情况下使用无符号类型,在需要表示数字的情况下使用有符号类型。不幸的是,C以其现有方式区分了这些细微差别,但这就是它们所是的。

6

一般来说这是正确的。如果不知道你为什么要寻找差异,我想不出其他有符号和无符号之间的不同点。


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