429

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

  1. 无符号可以持有更大的正值,没有负值。
  2. 无符号使用前导位作为值的一部分,而有符号版本使用最左边的位来识别数字是正数还是负数。
  3. 有符号整数可以同时包含正数和负数。

还有其他区别吗?

4

16 回答 16

370

无符号可以持有更大的正值,没有负值。

是的。

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

有不同的表示有符号整数的方法。最容易可视化的是使用最左边的位作为标志(符号和幅度),但更常见的是二进制补码。两者都在大多数现代微处理器中使用——浮点使用符号和幅度,而整数运算使用二进制补码。

有符号整数可以同时包含正数和负数。

是的。

于 2008-10-29T18:31:36.740 回答
96

我将在 x86 上讨论硬件级别的差异。除非您正在编写编译器或使用汇编语言,否则这几乎无关紧要。但很高兴知道。

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

“本地支持”是什么意思?基本上我的意思是有一组用于无符号数字的指令和另一组用于有符号数字的指令。无符号数可以与有符号数位于相同的寄存器中,实际上您可以混合有符号和无符号指令而不必担心处理器。由编译器(或汇编程序员)来跟踪数字是否有符号,并使用适当的指令。

首先,二进制补码具有加减法与无符号数相同的性质。数字是正数还是负数都没有区别。(所以你只要继续前进,ADDSUB的数字就不用担心了。)

当进行比较时,差异开始显现。x86 有一种区分它们的简单方法:上方/下方表示无符号比较,大于/小于表示有符号比较。(例如JAE,表示“如果高于或等于则跳转”并且是无符号的。)

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

最后:如果你想检查溢出,你会对有符号数和无符号数做不同的检查。

于 2008-11-19T08:12:53.570 回答
78

他只问签名和未签名。不知道为什么人们要在其中添加额外的东西。让我告诉你答案。

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

  2. 签名:它由负值和正值组成,但格式不同,例如

    • 0 至 +127
    • -1 到 -128

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

于 2014-05-15T07:07:23.343 回答
18

根据我们在课堂上学到的知识,有符号整数可以表示正数负数,而无符号整数只能表示非负数。

例如,查看一个8 位数字:

0符号255

有符号值范围从-128127

于 2016-01-26T23:19:31.710 回答
17

为了完整起见,请注意几点:

  • 这个答案只讨论整数表示。浮点数可能还有其他答案;

  • 负数的表示可以变化。今天使用的最常见的(到目前为止 - 它在今天几乎是普遍的)是二进制补码。其他表示包括一个补码(非常罕见)和有符号幅度(非常罕见 - 可能仅用于博物馆作品),它们只是使用高位作为符号指示符,其余位表示数字的绝对值。

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

  • 当使用一个补码或有符号幅度时,您可以将零表示为正数或负数(这是通常不使用这些表示的几个原因之一)。

于 2008-10-29T19:11:52.183 回答
11

除了第 2 点之外的一切都是正确的。有符号整数有许多不同的表示法,一些实现使用第一个,其他使用最后一个,还有一些使用完全不同的东西。这一切都取决于您正在使用的平台。

于 2008-10-29T18:31:18.210 回答
10

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

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

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

(可能应该转换第二个字节,但我猜编译器会做正确的事情)

使用带符号的值,您将不得不担心符号扩展并执行以下操作:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
于 2011-04-29T06:57:41.933 回答
6

除了其他人所说的之外,在 C 中,您不能溢出无符号整数。该行为被定义为模算术。您可以溢出一个有符号整数,理论上(尽管在当前主流系统上不是实践中),溢出可能会触发错误(可能类似于除以零错误)。

于 2008-10-29T18:43:52.647 回答
5

Signed integers in C represent numbers. If a and b are variables of signed integer types, the standard will never require that a compiler make the expression a+=b store into a anything other than the arithmetic sum of their respective values. To be sure, if the arithmetic sum would not fit into a, the processor might not be able to put it there, but the standard would not require the compiler to truncate or wrap the value, or do anything else for that matter if values that exceed the limits for their types. Note that while the standard does not require it, C implementations are allowed to trap arithmetic overflows with signed values.

Unsigned integers in C behave as abstract algebraic rings of integers which are congruent modulo some power of two, except in scenarios involving conversions to, or operations with, larger types. Converting an integer of any size to a 32-bit unsigned type will yield the member corresponding to things which are congruent to that integer mod 4,294,967,296. The reason subtracting 3 from 2 yields 4,294,967,295 is that adding something congruent to 3 to something congruent to 4,294,967,295 will yield something congruent to 2.

Abstract algebraic rings types are often handy things to have; unfortunately, C uses signedness as the deciding factor for whether a type should behave as a ring. Worse, unsigned values are treated as numbers rather than ring members when converted to larger types, and unsigned values smaller than int get converted to numbers when any arithmetic is performed upon them. If v is a uint32_t which equals 4,294,967,294, then v*=v; should make v=4. Unfortunately, if int is 64 bits, then there's no telling what v*=v; could do.

Given the standard as it is, I would suggest using unsigned types in situations where one wants the behavior associated with algebraic rings, and signed types when one wants to represent numbers. It's unfortunate that C drew the distinctions the way it did, but they are what they are.

于 2014-04-25T22:33:55.487 回答
5

一般来说,这是正确的。在不了解您为什么要寻找差异的更多信息的情况下,我想不出有符号和无符号之间的任何其他区别。

于 2008-10-29T18:30:24.560 回答
4

(回答第二个问题)仅使用符号位(而不是 2 的补码),您可以得到 -0。不是很漂亮。

于 2008-10-29T18:35:47.887 回答
4
  1. 是的,无符号整数可以存储大值。
  2. 不,有不同的方式来显示正值和负值。
  3. 是的,有符号整数可以包含正值和负值。
于 2013-04-25T09:45:26.583 回答
3

无符号整数比有符号整数更容易让你陷入特定的陷阱。陷阱来自这样一个事实,虽然上面的 1 和 3 是正确的,但两种类型的整数都可以被分配一个超出它可以“持有”的范围的值,并且它将被静默转换。

unsigned int ui = -1;
signed int si = -1;

if (ui < 0) {
    printf("unsigned < 0\n");
}
if (si < 0) {
    printf("signed < 0\n");
}
if (ui == si) {
    printf("%d == %d\n", ui, si);
    printf("%ud == %ud\n", ui, si);
}

当你运行它时,即使这两个值都被赋值为 -1 并且声明不同,你也会得到以下输出。

signed < 0
-1 == -1
4294967295d == 4294967295d
于 2011-02-04T21:35:53.970 回答
0

C 中有符号和无符号值之间唯一保证的区别是有符号值可以是负数、0 或正数,而无符号数只能是 0 或正数。问题是 C 没有定义类型的格式(所以你不知道你的整数是二进制补码)。严格来说,你提到的前两点是不正确的。

于 2010-07-12T01:58:38.180 回答
0

在嵌入式系统上编程时必须使用无符号整数。在循环中,当不需要有符号整数时,使用无符号整数将节省设计此类系统所需的安全性。

于 2014-01-14T19:47:49.127 回答
0

我在这方面找到的最佳答案是IBM引用了XDR 标准

整数

XDR 有符号整数是一段 32 位数据,它对 [-2147483648,2147483647] 范围内的整数进行编码。整数以二进制补码表示。最高和最低有效字节分别是 0 和 3。整数的数据描述是整数。

无符号整数

XDR 无符号整数是一段 32 位数据,它对 [0,4294967295] 范围内的非负整数进行编码。它由一个无符号二进制数表示,其最高和最低有效字节分别为 0 和 3。无符号整数的数据描述是无符号的。

参见维基百科上的XDR 标准

于 2022-01-08T22:50:49.867 回答