有符号整数与无符号整数

Posted

技术标签:

【中文标题】有符号整数与无符号整数【英文标题】:Signed versus Unsigned Integers 【发布时间】:2010-09-19 20:36:00 【问题描述】:

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

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

还有其他区别吗?

【问题讨论】:

因为0 is neither positive nor negative,对于无符号整数,使用术语非负值而不是正值更为合适。 【参考方案1】:

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

是的。

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

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

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

是的。

【讨论】:

我不确定这是否正是那个文本,但我找到了另一个链接。转到 PDF 的第 9 页(实际上是本书的第 38 页),您可以看到名为 Data Representation 的部分(第 1.3 节)。它对上面所说的所有事情都有解释。 lms.uop.edu.jo/lms/pluginfile.php/2420/mod_resource/content/1/…【参考方案2】:

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

首先,x86 原生支持two's complement 表示有符号数字。您可以使用其他表示,但这需要更多指令,而且通常会浪费处理器时间。

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

首先,二进制补码具有加减法与无符号数相同的特性。数字是正数还是负数都没有区别。 (所以您只需继续使用ADDSUB 您的号码,无需担心。)

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

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

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

【讨论】:

【参考方案3】:

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

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

    有符号:它由负值和正值组成,但格式不同,例如

    0 到 +127 -1 到 -128

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

【讨论】:

不错。简单的。简洁的。干得好。【参考方案4】:

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

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

无符号0255

有符号 值范围从 -128127

【讨论】:

【参考方案5】:

为了完整性,只需要几点:

此答案仅讨论整数表示。浮点数可能还有其他答案;

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

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

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

【讨论】:

如果我写 unsigned int a = -2 和 signed int b = -2 ,底层表示是否相同,我知道无符号数给出负值是不好的,但如果我给它,底层的表示是什么? 次要问题:符号和幅度用于 IEEE 浮点,因此实际上很常见。 :-)【参考方案6】:

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

【讨论】:

这是小端和大端的东西吗? little vs. big endian 与平台上的字节顺序有关。小端可能会做 0xFF 0xFE 0x7F 而大端会做 0x7F 0xFE 0xFF。【参考方案7】:

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

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

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

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

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

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

【讨论】:

【参考方案8】:

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

【讨论】:

请注意,有符号整数溢出确实会触发未定义的行为,现代编译器非常积极地发现这一点并利用它以意想不到但技术上合法的方式修改您的程序,因为它们被允许假设未定义的行为不会发生——粗略地说。现在这个问题比 7 年前要严重得多。【参考方案9】:

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

【讨论】:

【参考方案10】:

C 中的有符号整数表示数字。如果ab 是有符号整数类型的变量,则标准永远不会要求编译器将表达式a+=b 存储到a 中,而不是它们各自值的算术和。可以肯定的是,如果算术和不适合a,处理器可能不能把它放在那里,但标准不会要求编译器截断或包装值,或者如果值超出其类型的限制,请为此做任何其他事情。请注意,虽然标准没有要求,但允许 C 实现使用有符号值捕获算术溢出。

C 中的无符号整数表现为整数的抽象代数环,这些整数以 2 的某个幂为模全等,但涉及到更大类型的转换或操作的场景除外。将 any 大小的整数转换为 32 位无符号类型将产生与该整数 mod 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 以它的方式进行区分,但它们就是这样。

【讨论】:

【参考方案11】:
    是的,无符号整数可以存储大值。 不,有不同的方式来显示正值和负值。 是的,有符号整数可以包含正值和负值。

【讨论】:

【参考方案12】:

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

【讨论】:

只是为了补充这个答案,基本上这意味着 10 == 00 其中这两个数字都是基数 2。【参考方案13】:

无符号整数比有符号整数更容易让你陷入特定的陷阱。陷阱来自这样一个事实,虽然上面的 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

【讨论】:

【参考方案14】:

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

【讨论】:

【参考方案15】:

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

【讨论】:

【参考方案16】:

感谢IBM 引用XDR standard:

整数

XDR 有符号整数是一段 32 位的数据,用于编码 [-2147483648,2147483647] 范围内的整数。整数是 以二进制补码表示。最多和最少 有效字节分别为 0 和 3。数据说明 整数是整数。

无符号整数

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

参见Wikipedia上的XDR 标准

【讨论】:

以上是关于有符号整数与无符号整数的主要内容,如果未能解决你的问题,请参考以下文章

有符号整数比较v.s.无符号整数比较

Verilog -- 有符号与无符号运算

有符号和无符号整型数据溢出问题

如何在 Rust 中将有符号整数添加到无符号整数,检查无符号溢出?

大小应该使用有符号整数还是无符号整数?

正确解释有符号与无符号