当前位置: 代码迷 >> 汇编语言 >> 有符号数和无符号数到底有什么区别?该怎么处理
  详细解决方案

有符号数和无符号数到底有什么区别?该怎么处理

热度:7318   发布时间:2013-02-26 00:00:00.0
有符号数和无符号数到底有什么区别?
假如AL=20H,BL=10H,当执行CMP AL,BL后,问:
(1)若AL,BL中内容是两个无符号数,比较结果如何?影响哪几个标志位?
(2)若AL,BL中内容是两个有符号数,比较结果如何?影响哪几个标志位?
有符号数和无符号数到底有什么区别,请帮忙指点一下。

------解决方案--------------------------------------------------------
有符号数和无符号数在CPU和储存器中是不区分的,只有一些特殊指令分为有符号和无符号指令,例如imul、idiv、sar、jl、jg等。
------解决方案--------------------------------------------------------

(l)AL=2OH,BL=1OH,O=0,S=0,Z=0,A=0,P=0,C=0.
(2)因为两个都是符号正数,其结果与(l)相同.

答案来自网络
:)
------解决方案--------------------------------------------------------
c:\>debug 
-a
0B94:0100 mov al,20
0B94:0102 mov bl,10
0B94:0104 cmp al,bl
0B94:0106
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B94 ES=0B94 SS=0B94 CS=0B94 IP=0100 NV UP EI PL NZ NA PO NC
0B94:0100 B020 MOV AL,20
-g 0102

AX=0020 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B94 ES=0B94 SS=0B94 CS=0B94 IP=0102 NV UP EI PL NZ NA PO NC
0B94:0102 B310 MOV BL,10
-g 0104

AX=0020 BX=0010 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B94 ES=0B94 SS=0B94 CS=0B94 IP=0104 NV UP EI PL NZ NA PO NC
0B94:0104 38D8 CMP AL,BL
-g 0106

AX=0020 BX=0010 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B94 ES=0B94 SS=0B94 CS=0B94 IP=0106 NV UP EI PL NZ NA PO NC
0B94:0106 26 ES:
0B94:0107 3B5401 CMP DX,[SI+01] ES:0001=FF20
-g
C:\>
------解决方案--------------------------------------------------------
有符号数和无符号数探讨

这个问题,要是简单的理解,是很容易的,不过要是考虑的深了,还真有些东西呢。
下面我就把这个东西尽量的扩展一点,深入一点和大家说说。
 
一、只有一个标准!
 
在汇编语言层面,声明变量的时候,没有 signed 和 unsignde 之分,汇编器统统,将你输入的整数字面量当作有符号数处理成补码存入到计算机中,只有这一个标准!汇编器不会区分有符号还是无符号然后用两个标准来处理,它统统当作有符号的!并且统统汇编成补码!也就是说,db -20 汇编后为:EC ,而 db 236 汇编后也为 EC 。这里有一个小问题,思考深入的朋友会发现,db 是分配一个字节,那么一个字节能表示的有符号整数范围是:-128 ~ +127 ,那么 db 236 超过了这一范围,怎么可以?是的,+236 的补码的确超出了一个字节的表示范围,那么拿两个字节(当然更多的字节更好了)是可以装下的,应为:00 EC,也就是说 +236的补码应该是00 EC,一个字节装不下,但是,别忘了“截断”这个概念,就是说最后汇编的结果被截断了,00 EC 是两个字节,被截断成 EC ,所以,这是个“美丽的错误”,为什么这么说?因为,当你把 236 当作无符号数时,它汇编后的结果正好也是 EC ,这下皆大欢喜了,虽然汇编器只用一个标准来处理,但是借用了“截断”这个美丽的错误后,得到的结果是符合两个标准的!也就是说,给你一个字节,你想输入有符号的数,比如 -20 那么汇编后的结果是符合有符号数的;如果你输入 236 那么你肯定当作无符号数来处理了(因为236不在一个字节能表示的有符号数的范围内啊),得到的结果是符合无符号数的。于是给大家一个错觉:汇编器有两套标准,会区分有符号和无符号,然后分别汇编。其实,你们被骗了。:-)
 
二、存在两套指令!
 
第一点说明汇编器只用一个方法把整数字面量汇编成真正的机器数。但并不是说计算机不区分有符号数和无符号数,相反,计算机对有符号和无符号数区分的十分清晰,因为计算机进行某些同样功能的处理时有两套指令作为后备,这就是分别为有符号和无符号数准备的。但是,这里要强调一点,一个数到底是有符号数还是无符号数,计算机并不知道,这是由你来决定的,当你认为你要处理的数是有符号的,那么你就用那一套处理有符号数的指令,当你认为你要处理的数是无符号的,那就用处理无符号数的那一套指令。加减法只有一套指令,因为这一套指令同时适用于有符号和无符号。下面这些指令:mul div movzx … 是处理无符号数的,而这些:imul idiv movsx … 是处理有符号的。
举例来说:
内存里有 一个字节x 为:0x EC ,一个字节 y 为:0x 02 。当把x,y当作有符号数来看时,x = -20 ,y = +2 。当作无符号数看时,x = 236 ,y = 2 。下面进行加运算,用 add 指令,得到的结果为:0x EE ,那么这个 0x EE 当作有符号数就是:-18 ,无符号数就是 238 。所以,add 一个指令可以适用有符号和无符号两种情况。(呵呵,其实为什么要补码啊,就是为了这个呗,:-))
乘法运算就不行了,必须用两套指令,有符号的情况下用imul 得到的结果是:0x FF D8 就是 -40 。无符号的情况下用 mul ,得到:0x 01 D8 就是 472 。(参看文后附录2例程)
 
三、可爱又可怕的c语言。
 
为什么又扯到 c 了?因为大多数遇到有符号还是无符号问题的朋友,都是c里面的 signed 和 unsigned 声明引起的,那为什么开头是从汇编讲起呢?因为我们现在用的c编译器,无论gcc 也好,vc6 的cl 也好,都是将c语言代码编译成汇编语言代码,然后再用汇编器汇编成机器码的。搞清楚了汇编,就相当于从根本上明白了c,而且,用机器的思维去考虑问题,必须用汇编。(我一般遇到什么奇怪的c语言的问题都是把它编译成汇编来看。)
 
C 是可爱的,因为c符合kiss 原则,对机器的抽象程度刚刚好,让我们即提高了思维层面(比汇编的机器层面人性化多了),又不至于离机器太远(像c# ,java之类就太远了)。当初K&R 版的c就是高级一点的汇编……:-)
 
C又是可怕的,因为它把机器层面的所有的东西都反应了出来,像这个有没有符号的问题就是一例(java就不存在这个问题,因为它被设计成所有的整数都是有符号的)。为了说明它的可怕特举一例:
 
#include <stdio.h> 
#include <string.h> 
 
int main()
{
int x = 2; 
char * str = "abcd"; 
int y = (x - strlen(str) ) / 2;

printf("%d\n",y);