我正确地说无符号整数和有符号整数之间的区别是:
- 无符号整数可以容纳更大的正值,但不能存储负值。
- 无符号整数使用最高位作为值的一部分,而有符号版本使用最高位来标识数字的正负性。
- 有符号整数可以容纳正数和负数。
还有其他区别吗?
我将讨论x86硬件层面的差异,这主要与编写编译器或使用汇编语言相关,但了解此知识还是很好的。
首先,x86原生支持有符号数的 二进制补码 表示。您可以使用其他表示方式,但这会需要更多指令,并且通常会浪费处理器时间。
什么叫做“原生支持”?基本上,这意味着存在一组用于无符号数的指令和一组用于有符号数的指令。无符号数可以存储在与有符号数相同的寄存器中,实际上,您可以混合使用有符号和无符号指令而不必担心处理器。编译器(或汇编程序员)需要跟踪一个数字是否为有符号,并使用适当的指令。
首先,二进制补码具有加法和减法性质,与无符号数完全相同。这使得该数字是正数还是负数没有任何影响。(因此,您只需毫无顾虑地执行ADD
和 SUB
操作即可。)
当涉及比较时,差异开始显现:x86有一种简单的方法来区分它们:above/below表示无符号比较,greater/less than 表示有符号比较。(例如,JAE
表示“跳转到以上或等于”,是无符号的)
还有两组乘法和除法指令来处理有符号整数和无符号整数。
最后:如果您想检查溢出,例如检查有符号数和无符号数,那么需要使用不同的方法。
他只问了有符号和无符号的问题,不知道为什么有人要添加额外的内容。让我告诉你答案。
无符号:它仅包含非负值,即0到255。
有符号:它包含正数和负数,但格式不同,如下:
这个解释是关于8位数字系统的。
为了完整起见,以下是一些要点:
本答案仅讨论整数表示法。对于浮点数可能有其他答案;
负数的表示可以有所不同。目前使用最广泛(几乎普遍)的是二进制补码。其他表示法包括原码反码(相当罕见)和带符号数值(非常罕见 - 可能只在博物馆里使用),后者只是使用高位作为符号指示符,其余位表示数值的绝对值。
当使用二进制补码时,变量可以表示比正数更大的负数范围(加上一个)。这是因为零被包括在“正数”中(因为零的符号位未设置),而不是负数。这意味着最小负数的绝对值无法表示。
当使用原码反码或带符号数值时,零可以被表示为正数或负数(这是这些表示法通常不使用的原因之一)。
除了第二点之外,其余都是正确的。有许多不同的有符号整数表示法,一些实现使用第一个,另一些使用最后一个,还有些则完全使用不同的表示法。这完全取决于你所使用的平台。
另一个区别是当你在不同大小的整数之间进行转换时。
例如,如果你从字节流中提取一个整数(假设简单起见为16位),使用无符号值,你可以这样做:
i = ((int) b[j]) << 8 | b[j+1]
(也许应该将第二个字节转换为特定类型,但我猜编译器会做正确的事情)
对于带符号值,您需要担心符号扩展并进行以下操作:
i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
除了其他人说的之外,在C语言中,您无法溢出无符号整数;其行为被定义为模算术。您可以溢出有符号整数,并且理论上(尽管在当前主流系统上实践中不会发生),溢出可能会触发故障(可能类似于除以零故障)。
a
和b
是有符号整数类型的变量,则标准永远不会要求编译器将表达式a += b
储存到a
中除了它们各自值的算术和之外的任何其他内容。确保如果算术和无法适合a
,则处理器可能无法将其放置在那里,但是标准不会要求编译器截断或包装值,或者对于超过类型限制的值执行任何其他操作。请注意,尽管标准不要求,但C实现允许使用带符号值捕获算术溢出。int
的无符号值执行任何算术运算时,无符号值被视为数字而不是环成员。如果v
是等于4,294,967,294
的uint32_t
,则v *= v;
应该使v = 4
。不幸的是,如果int
是64位,则无法确定v *= v;
会做什么。一般来说这是正确的。如果不知道你为什么要寻找差异,我想不出其他有符号和无符号之间的不同点。