签名与无符号整数

时间:2008-10-29 18:28:18

标签: language-agnostic integer unsigned signed

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

  1. 无符号可以保持较大的正值,而不是负值。
  2. 无符号使用前导位作为值的一部分,而签名版本使用最左侧位来识别数字是正数还是负数。
  3. 有符号整数可以包含正数和负数。
  4. 还有其他差异吗?

15 个答案:

答案 0 :(得分:314)

  

无符号可以保持较大的正值,也没有负值。

是。

  

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

表示有符号整数的方法有很多种。最容易想象的是使用最左边的位作为标志(sign and magnitude),但更常见的是two's complement。两者都在大多数现代微处理器中使用 - 浮点使用符号和幅度,而整数运算使用二进制补码。

  

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

答案 1 :(得分:89)

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

首先,x86对签名号码的two's complement表示具有原生支持。您可以使用其他表示形式,但这需要更多指令,通常会浪费处理器时间。

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

首先,两个补码数具有加法和减法与无符号数相同的特性。数字是正数还是负数没有区别。 (所以你只需继续ADDSUB你的号码而不必担心。)

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

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

最后:如果你想检查溢出,你会对签名和无符号数字采用不同的方法。

答案 2 :(得分:55)

他只询问签名和未签名。不知道为什么人们会在这里添加额外的东西。我来告诉你答案。

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

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

    • 0到+127
    • -1到-128
  3. 这个解释是关于8位数字系统。

答案 3 :(得分:15)

完整性只需几点:

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

  • 负数的表示可能会有所不同。今天使用的最常见的(到目前为止几乎是普遍的)是两个补码。其他表示包括的补(比较少见)和符号的振幅(难以觉察罕见 - 可能只在博物馆展品使用),这是简单地使用高比特作为与一个标志指示保留代表数字绝对值的位。

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

  • 当使用一的补码或符号量值可以具有零表示,可以是正数或负数(这是有几个原因,这些表示是通常不使用的一种)。

答案 4 :(得分:13)

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

例如,查看 8位号码:

未签名0255

签名的值范围从-128127

答案 5 :(得分:11)

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

答案 6 :(得分:10)

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

例如,如果要从字节流中提取整数(为简单起见,则为16位),使用无符号值,可以执行以下操作:

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

(应该强制转换2 nd 字节,但我猜测编译器会做正确的事情)

使用签名值,您将不得不担心签名扩展并执行:

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

答案 7 :(得分:4)

一般来说这是正确的。在不知道为什么要寻找差异的情况下,我无法想到签名和未签名之间的任何其他区别。

答案 8 :(得分:4)

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

答案 9 :(得分:4)

除了其他人所说的,在C中,你不能溢出无符号整数;行为被定义为模数运算。你可以溢出有符号整数,理论上(虽然在当前主流系统中没有实际),溢出可能会触发故障(可能类似于除零故障)。

答案 10 :(得分:4)

  1. 是的,无符号整数可以存储大值。
  2. 不,有不同的方法来显示正面和负面的价值。
  3. 是的,有符号整数可以包含正值和负值。

答案 11 :(得分:3)

无符号整数更有可能在特定陷阱中捕获您而不是有符号整数。陷阱来自1和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

答案 12 :(得分:3)

C中的有符号整数表示数字。如果ab是有符号整数类型的变量,则标准将永远不要求编译器使表达式a+=b存储到a除了它们的算术总和之外的任何内容各自的价值观可以肯定的是,如果算术和不适合a,处理器可能无法将其放在那里,但标准不要求编译器截断或包装值,如果超出其类型限制的值,则执行其他任何操作。请注意,虽然标准不要求它,但允许C实现捕获带有符号值的算术溢出。

C中的无符号整数表现为整数的抽象代数环,除了涉及对较大类型的转换或操作的情况外,它们是2的幂的一致模。将任何大小的整数转换为32位无符号类型将产生对应于与该整数mod 4,294,967,296一致的事物的成员。从2中减去3得到4,294,967,295的原因是,将一些与3一致的东西添加到4,294,967,295的某些东西将产生与2一致的东西。

抽象代数环类型通常是有用的东西;不幸的是,C使用签名作为一个类型是否应该表现为环的决定因素。更糟糕的是,无符号值在转换为较大类型时被视为数字而不是环成员,而在对它们执行任何算术时,小于int的无符号值将被转换为数字。如果vuint32_t等于4,294,967,294,那么v*=v;应该v=4。不幸的是,如果int是64位,那么就不知道v*=v;可以做什么。

鉴于标准本身,我建议在需要与代数环相关联的行为的情况下使用无符号类型,并在需要表示数字时使用有符号类型。不幸的是,C以它的方式绘制了区别,但它们就是它们。

答案 13 :(得分:0)

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

答案 14 :(得分:0)

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