机器如何识别有符号数和无符号数?

机器如何识别有符号数和无符号数?

机器为了简化有符号数的操作引入了补码表示法(大多数PC都这样表示),运算中连同符号位一起运算,而ADD,SUB通常并不区分有符号数和无符号数,而是通过FLAGS中的一些标志位来判断,这种判断如何实现?带符号数中负数的补码表示与数本身并不相同,若某个无符号数最高位为1,则对无符号数的表示使用补码还是原码?机器在存放数的时候是否要标识数是有符号还是无符号的?
对于上述的问题在书上和网上查到的资料主要都是针对有符号数的阐述,对于无符号数没有更多的涉及,能否推荐一些资料

机器如何识别有符号数和无符号数?

机器在存储时不区分有符号数和无符号数,只是在做一些比较和位扩展时用到的寄存器和机器指令不相同
具体看《深入理解计算机系统》第二,三章节

TOP

 

机器如何识别有符号数和无符号数?

楼上的仁兄是不是把<<深入理解计算机系统>>都看了? 我这几天也在看这本书但是看到了第三章的题就不会做了,想请叫一下各位: 第3章的家庭作业 3.38 程序的实现是: /* Bomb program that is solved using a buffer overflow attack */ #include #include #include /* Like gets, except that characters are typed as pairs of hex digits. Nondigit characters are ignored. Stops when encounters newline */ char *getxs(char *dest) { int c; int even = 1; /* Have read even number of digits */ int otherd = 0; /* Other hex digit of pair */ char *sp = dest; while ((c = getchar()) != EOF && c != '\n') { if (isxdigit(c)) { int val; if ('0' <= c && c <= '9') val = c - '0'; else if ('A' <= c && c <= 'F') val = c - 'A' + 10; else val = c - 'a' + 10; if (even) { otherd = val; even = 0; } else { *sp++ = otherd * 16 + val; even = 1; } } } *sp++ = '\0'; return dest; } /* $begin getbuf-c */ int getbuf() { char buf[12]; getxs(buf); return 1; } void test() { int val; printf("Type Hex string:"); val = getbuf(); printf("getbuf returned 0x%x\n", val); } /* $end getbuf-c */ int main() { int buf[16]; /* This little hack is an attempt to get the stack to be in a stable position */ int offset = (((int) buf) & 0xFFF); int *space = (int *) alloca(offset); *space = 0; /* So that don't get complaint of unused variable */ test(); return 0; } 要求是: 利用缓冲区溢出,输入一个适当的十六进制字符串, 使getbuf对teest返回-559038737(0xdeadbeef), getxs()函数只接受0-9 ,A-F,a-f这22字符的十六进制 程序的输出向这样: localhost@localhost root>./bufbomb Type Hex String:30 31 32 33 34 getbuf returned:0x1 如果方便的话也可以发到我的邮箱里:li_bing_wai@yahoo.com.cn 谢谢了

TOP

 

机器如何识别有符号数和无符号数?

你的帖子已经回了

TOP

 

机器如何识别有符号数和无符号数?

谢谢了

TOP

 

机器如何识别有符号数和无符号数?

//这种判断如何实现?
  硬件实现的。
//若某个无符号数最高位为1,则对无符号数的表示使用补码还是原码?
   我想是原码
//机器在存放数的时候是否要标识数是有符号还是无符号的?
   机器不会区分标实数的符号的。(否则硬件实现代价太大了,我想)
以上是我的推想,也不太确定。这些问题应该与机器架构、编译器和编程语言的类型检查相关。希望有人来回答一下,或推荐些资料。

TOP

 

机器如何识别有符号数和无符号数?

《深入理解计算机系统》  p57  :“两个数的w位二进制补码之和与无符号之和有完全相同的位级表示。实际上,大多数计算机使用同样的机器指令来执行无符号或者有符号加法”
至于c是如何处理有符号和无符号的,请自己阅读《深入理解计算机系统》第二章 信息的表示和处理

TOP

 

机器如何识别有符号数和无符号数?

[这个贴子最后由linyjg在 2005/01/09 08:40pm 第 1 次编辑]

对于机器码而言,机器指令操作码的倒数第二位用来指示是否为有符号操作数的,为1时指示是有符号操作数,为0时是无符号操作数,比如ADD指令,ADD 16位寄存器/32寄存器,有符号操作数,它被翻译成机器指令时的操作码是0x83,而ADD 16位寄存器/32寄存器,无符号操作数,它被翻译成机器指令时的操作码是0x81,具体资料可参考《Intel 微处理器结构、编程与接口》书后面所附的指令对照表及其Intel公司公布的《IA-32 Intel Architecture Software Developer’s Manual》PDF文档。

TOP

 

机器如何识别有符号数和无符号数?

请问楼上的朋友,哪里能找到原话?^_^,今天上午找了一下,感觉像大海捞针啊,可以告诉一下哪个版本的,多少页吗?
谢谢了

TOP

 

机器如何识别有符号数和无符号数?

原话当真是没有,我是系统地研究了计算机指令才得出结论的,事实上我参考了很多资料,《Intel 微处理器结构、编程与接口》是中文第六版,如果你有指令对照表那么请注意,指令操作码的倒数第二位可能用d或者s来表示,如果是d那么表示的是操作数的方向,如果是s那么就是用来表示符号的。如果对研究指令有兴趣希望多交流,我的邮箱是victor_yjg@sohu.com

TOP

 

机器如何识别有符号数和无符号数?

下面引用由linyjg在 2005/01/09 08:36pm 发表的内容:
对于机器码而言,机器指令操作码的倒数第二位用来指示是否为有符号操作数的,为1时指示是有符号操作数,为0时是无符号操作数,比如ADD指令,ADD 16位寄存器/32寄存器,有符号操作数,它被翻译成机器指令时的操作 ...
立即数区分符号数和无符号数是好理解的,但是如果是其他寻址,你举的例子中ADD 16位寄存器/32寄存器 有符号操作数中寄存器里面的数值是按照有符号还是无符号处理的呢?
谢谢

TOP

 

机器如何识别有符号数和无符号数?

就我所知,“机器指令操作码的倒数第二位用来指示是否为有符号操作数的,为1时指示是有符号操作数,为0时是无符号操作数,比如ADD指令,ADD 16位寄存器/32寄存器,有符号操作数,它被翻译成机器指令时的操作码是0x83,而ADD 16位寄存器/32寄存器,无符号操作数,它被翻译成机器指令时的操作码是0x81”如这样的指令有以下几个:ADC、ADD、AND、CMP、IMUL、OR、PUSH、SBB、SUB、XOR,而且这样的有符号立即数都是八位的,在2001年版《IA-32 Intel Architecture Software Developer’s Manual》第2卷PDF文档表述为“sign-extended imm8”(来至3-21页的ADD指令)。而对于NASM汇编器而言(其他汇编器没有试过),它翻译指令时并没有将这样的指令翻译成前面所述的0x83或者0x81的操作码,而是将负数转化成补码来翻译。如:
mov ax,-1
add ax,-1
它最终得到的机器码是:B8 FF FF 05 FF FF 
其中B8是mov ax 而FF FF 是-1;05是add ax 而FF FF 是-1
可见它并没有把第二条指令add的操作码翻译成0x81,可能符号的处理与汇编器有关系吧,至于寄存器的符号问题,从上面的第一条指令可以得出ax的值肯定是FF FF了。

TOP

 

有符号无符号

原帖由  linyjg 于 2005-1-17 21:03 发表 
就我所知,“机器指令操作码的倒数第二位用来指示是否为有符号操作数的,为1时指示是有符号操作数,为0时是无符号操作数,比如ADD指令,ADD 16位寄存器/32寄存器,有符号操作数,它被翻译成机器指令时的操作码是 ...



各位注意了,楼上这位同志的说法是错误的!!!我最近正在考虑这个问题,偶然搜索到这个帖子,发现这位的错误说法,为了后来的同志不至于被误导,我特意注册了一个名字,回下帖子。

这个问题要是考虑深了,还真有些东西呢,当然,要是简单的理解,那就很容易了。下面我就把这个东西尽量的扩展一点,深入一点和大家说说。

一、只有一个标准!

在汇编语言层面,声明变量的时候,没有 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就不存在这个问题,因为它被设计成所有的整数都是有符号的)。为了说明c的可怕特举一例:

#include <stdio.h> 
#include <string.h> 

int main()
{
        int x = 2; 
        char * str = "abcd"; 
        int y = (x - strlen(str) ) / 2;
        
        printf("%d\n",y);
}

结果应该是 -1 但是却得到:2147483647 。为什么?因为strlen的返回值,类型是size_t,也就是unsigned int ,与 int 混合计算时类型被自动转换了,结果自然出乎意料。。。
观察编译后的代码,除法指令为 div ,意味无符号除法。
解决办法就是强制转换,变成 int y = (int)(x - strlen(str) ) / 2; 强制向有符号方向转换(编译器默认正好相反),这样一来,除法指令编译成 idiv 了。我们知道,就是同样状态的两个内存单位,用有符号处理指令 imul ,idiv 等得到的结果,与用 无符号处理指令mul,div等得到的结果,是截然不同的!所以牵扯到有符号无符号计算的问题,特别是存在讨厌的自动转换时,要倍加小心!(这里自动转换时,无论gcc还是cl都不提示!!!)


为了避免这些错误,建议,凡是在运算的时候,确保你的变量都是 signed 的。(完)



附录
1:顺便指出楼上那位同志错误的地方,《IA-32 Intel Architecture Software Developer’s Manual》第2卷PDF文档表述为“sign-extended imm8”,这个sign-extended 是符号扩展的意思,他理解成有符号数了。。。
说说符号扩展:当操作数进行长度扩展时,既要让操作数变长又不能改变原数值,所以就出现了符号扩展一说。比如 movsx ax, 0xEC  ,执行扩展后,ax的值为:0xFFEC,长度变长了,结果没变,都是 -20 。

2:两套乘法指令结果例程

;; 程序存储为 x.s 
;;--start--------------------------------------------------------

extern printf 
global main 

section .data
        str1: db "%x",0x0d,0x0a,0 
        n: db 0x02
section .text 
main: 
        xor eax,eax
        mov al, 0xec
        mul  byte [n]  ;有符号乘法指令为: imul

        push eax
        push str1
        call printf 
        
        add esp,byte 4 
        ret 
;;--end---------------------------------------------------------------

编译步骤:
1. nasm -felf x.s  
2. gcc x.o

ubuntu7.04 下用nasm和gcc编译通过。结果符合文章所述。


最后:
如果我有什么错误的地方请大家指正!
我的blog : http://blog.csdn.net/band_of_brothers/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值