我正在使用MASM 14.0进行组装,我与下面代码的输出混淆。
TITLE Exercise 4 from chapter 4
; Author : Saad Ahmed
INCLUDE Irvine32.inc
.code
main PROC
mov eax, 0
mov al, 255
add al, 1
call DumpRegs ; Display registers
mov al, 127
add al, 1
call DumpRegs ; Display registers
exit
main ENDP
END main
这两个算术运算都是在无符号整数255和127上完成的。
然而,CPU将第一个操作255视为无符号整数,并设置进位标志,当将1添加到无符号255时会出现这种情况。
完整的状态标志是CF=1 SF=0 ZF=1 OF=0 AF=1 PF=1,eax为0
但是,第二个操作在设置溢出标志时将127视为有符号整数,如果将127加1,则会发生溢出标志。
完整的状态标志是CF=0 SF=1 ZF=0 OF=1 AF=1 PF=0,eax为0。
问题是CPU如何决定第一个操作是在无符号255上完成的,而另一个操作是在有符号整数上完成的?
二的补码的优点是CPU不需要知道。
它只对无符号字节进行加法。
设置进位标志是因为255 1不适合8位(显然)。
设置溢出标志是因为两个操作数的MSB为0,输出的MSB为1——表明如果您认为这是有符号算术,则表示您已经溢出。如果您认为它是无符号算术,那么您应该忽略该标志。请参阅这篇维基百科文章。
对于使用二补码的加法(和减法),就逻辑而言,没有符号或无符号的概念。乘和除,是的,由于需要符号扩展。
取从000到111的所有3位数字的组合,将它们添加到所有3位数字的组合中,这是可以管理的。如果你愿意,可以写一个程序,也可以手工编写。或者只做角落案例。对于每个操作数,使用两个补码将每个操作数检查为有符号或无符号。您将注意到,相同的加法也有效。1110=111。现在是1(-2)=-1还是16=7。两者都起作用了。
进位标志是无符号溢出,V标志是有符号溢出,这就是为什么我们同时计算这两个数字,这样用户就可以选择正确的条件值,谁知道这些数字是有符号还是无符号。这就是为什么当大于或等于时有符号跳转,而当大于或等于时有无符号跳转。
正是两人互补的美使这一切都起了作用。
乘法(和除法)是不同的,因为你必须签署扩展。二进制乘法有一个漂亮的特性,如果你仔细想想
abcd
* 0011
=======
abcd
abcd
0000
0000
=======
位是1或0,所以你要把顶部的数字乘以1或0,你要么加它移位,要么不加。但是也要注意,你很快就会溢出。我们从小学就知道n^x*n^y=n^(x y)。如果你的寄存器是Z位宽,那么操作数的最高有效位位置在相加时不能大于Z,否则它会溢出。四位0010*0010应该可以,但是0010*1000会溢出。正确的方法是结果是操作数的两倍宽。
如果我想乘以1111*0010呢?
这基本上是
0000
1111
0000
+0000
========
0011110
等等,那是15(0b1111)还是-1(0b1111)?-1 * 2 = -2这不是我们上面得到的,我们做了一个无符号乘法来做一个有符号乘法,我们必须签署扩展并从左边抛出位
11..1111
*00..0010
=========
00000000
1111111
000000
00000
=========
11111110
这给出了两个四位寄存器1111和0010的有符号乘法的正确答案。
加法之所以有效,是因为您只关心一列。每列有一个进位、两个操作数、一个结果和一个进位。然后你可以把它级联到你想要的任何宽度。对于一个位,你有0和1。0只是零,不是正负零,1可以是1或-1。我发现通过多个列的组合更容易,但这是可以做到的。此外,进位是0,所以我不需要表示它操作数a、操作数b、进位和结果
00 00 0 + 0 = 0
01 01 0 + 1 = 1; 0 + (-1) = -1
10 01 1 + 0 = 1; (-1) + 0 = -1
11 10 1 + 1 = 0 unsigned overflow. -1 + 1 = 0, 1 + -1 = 0, -1 + -1 = 0 signed overflow
从技术上讲,在最后一种情况下,所有有符号的溢出都是有符号的溢出,这是您处理任意数量位的特殊情况,取一个三位寄存器100 100 = 000执行1是4 4=0无符号溢出还是有符号溢出的-4 -4 = 0?这就是为什么当您使用几个位并通过抛出1然后全零的问题情况的组合时更容易看到。
有符号溢出是当最重要列的进位与进位不匹配时。无符号溢出是当msbit的进位为1时。
逻辑中的减法是用加法来完成的,我们从小学就知道a-b=a(-b),我们从编程课上知道,要用两个补码取负数,就要倒过来加一。这很好,我们可以反转第二个操作数,反转lsbit的进位,使其成为一,或者反转并相加一。这就是工作原理。执行有时从alu中反转出来,以指示借用。你必须看看标志组合才能弄清楚这一点,一些处理器反转执行一些不执行。有时可以从带借位的减法中判断ISA是否有该指令。
我知道TL:DR…比你要求的要多。
我在看的书:CS-app 2。c有无符号和有符号的int类型,并且在大多数架构中使用二进制补码算法来实现有符号值;但是学了一些汇编代码之后,发现很少有指令区分无符号和有符号。所以我的问题是: > 区分有符号和无符号是编译器的责任吗?如果是,它是如何做到的? 谁实现两个补码算法——CPU还是编译器? 添加更多信息: 在学习了更多的指令后,实际上有一些指令区分有符号和无符号,例如setg、seta等。
有符号和无符号变量在按位运算上有区别吗?< br >例如,在处理无符号数字时:< br> 将得到00000101。 但当处理带符号的数字时会发生什么?
我正在设计一个简单的玩具指令集和附带的仿真器,并试图找出支持什么指令。在算术方面,我目前有无符号加法、减法、乘法和除法。然而,对于以下问题,我似乎找不到一个明确的答案:哪种算术运算符需要有符号版本,而无符号和二的补码有符号版本对哪一种是等价的? 例如,1111在2的补码中等于-1。如果你给它加1,假装它是一个无符号的数字,你会得到0000,即使把它想象成-1也是正确的。然而,这适用于所有数字吗?其
C语言有符号和无符号类型,如char和int。我不确定它是如何在程序集级别实现的,例如,在我看来,有符号和无符号的乘法会带来不同的结果,那么程序集是同时做无符号和有符号的算术,还是只做一个,这在某种程度上是针对不同情况模拟的?
考虑函数调用(调用< code>int sum(int,int)) 编译器如何确定函数调用 中使用的 不是逗号运算符? 注意:我不想在函数调用中实际使用逗号运算符。我只是想知道编译器如何知道它不是逗号运算符。
问题内容: 我了解Java中的无符号右移运算符“ >>>”是什么,但是为什么我们需要它,为什么我们不需要相应的无符号左移运算符? 问题答案: 该运营商允许你将和为32位和64位 无符号 整型,这是从Java语言缺少的。 当您移动不代表数值的内容时,这很有用。例如,您可以使用32位s 表示黑白位图图像,其中每个位图在屏幕上编码32个像素。如果需要将图像向右滚动,则希望将an左侧的位变为零,以便可以轻