378 language-agnostic unsigned signed integer
我是否正确地说有符号和无符号整数之间的区别是:
还有其他差异吗?
Art*_*ius 89
我将在x86上的硬件级别上进行分析.除非您正在编写编译器或使用汇编语言,否则这几乎无关紧要.但很高兴知道.
首先,X86具有原生的支持二进制补码符号数的表示.您可以使用其他表示形式,但这需要更多指令,通常会浪费处理器时间.
"原生支持"是什么意思?基本上我的意思是你有一组用于无符号数字的指令和另一套用于有符号数字的指令.无符号数字可以与有符号数字位于相同的寄存器中,实际上,您可以混合有符号和无符号指令,而无需担心处理器.由编译器(或汇编程序员)来跟踪数字是否已签名,并使用适当的指令.
首先,二进制补码数具有加法和减法与无符号数相同的特性.数字是正数还是负数没有区别.(所以你只需要继续,ADD并且SUB不用担心你的数字.)
在进行比较时,差异开始显现.x86有一种区分它们的简单方法:上/下表示无符号比较,大于/小于表示已签名比较.(例如,JAE"如果大于或等于跳跃"并且是未签名的.)
还有两组乘法和除法指令来处理有符号和无符号整数.
最后:如果你想检查溢出,你会对签名和无符号数做不同的处理.
小智 59
基本上他只询问签名和未签名.不知道为什么人们会在这里添加额外的东西.我来告诉你答案.
无符号:仅包含正值,即0到255.
签名:它包含负值和正值,但有不同的格式,如
这一切都是关于8位数系统的解释.
Mic*_*urr 15
完整性只需几点:
这个答案只讨论整数表示.浮点可能还有其他答案;
负数的表示可以变化.今天使用的最常见的(到目前为止 - 它几乎是通用的)是两个补充.其他表示包括一个补码(非常罕见)和有符号的幅度(很少见 - 可能仅用于博物馆作品),它只是使用高位作为符号指示符,其余位代表数字的绝对值.
当使用二进制补码时,变量可以表示比正数更大的负数范围(乘以1).这是因为"正"数字中包含零(因为符号位未设置为零),而不是负数.这意味着无法表示最小负数的绝对值.
当使用一个补码或有符号幅度时,您可以将零表示为正数或负数(这是通常不使用这些表示的几个原因之一).
Mik*_*een 10
另一个区别是当您在不同大小的整数之间进行转换时.
例如,如果要从字节流中提取整数(为简单起见,则为16位),使用无符号值,您可以执行以下操作:
i = ((int) b[j]) << 8 | b[j+1]
Run Code Online (Sandbox Code Playgroud)
(应该可能会转换第二个字节,但我猜测编译器会做正确的事情)
使用签名值,您将不得不担心签名扩展并执行:
i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
Run Code Online (Sandbox Code Playgroud)
除了其他人所说的,在 C 中,您不能溢出无符号整数;该行为被定义为模数算术。您可以溢出一个有符号整数,理论上(尽管在当前主流系统上没有实践),溢出可能会触发故障(可能类似于除以零故障)。
C 中的有符号整数表示数字。如果a和b是有符号整数类型的变量,则标准永远不会要求编译器将表达式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在对其执行任何算术时会被转换为数字。如果v是 auint32_t等于4,294,967,294,那么v*=v;应该使v=4。不幸的是,如果int是 64 位,那么不知道v*=v;能做什么。
鉴于目前的标准,我建议在需要与代数环相关的行为的情况下使用无符号类型,而在想要表示数字时使用有符号类型。不幸的是,C 按照它的方式进行了区分,但它们就是这样。