像3,4这样的数没无符号数和有符号数的区别是对的吗

格式:DOC ? 页数:2页 ? 上传日期: 20:40:48 ? 浏览次数:5 ? ? 978积分 ? ? 用稻壳阅读器打开

全文阅读已结束如果下载本文需要使用

该用户还上传了这些文档

}

无符号数和有符号数的区别数与無符号数做除法时双方都转为无符号数再做除法;

作为无符号数除以4时,向右移2位(左边补零)中间结果为0x3f ff ff ff

之后乘以4时,向左移位(右边補零)结果为oxff ff ff fc

该数字表示无符号数和有符号数的区别数-4,于是-4就被打印出来

【转】 有关C语言中无符号数和有符号数的区别/无符号数混匼运算的小问题

这两天的工作需要涉及到对无符合数,无符号数和有符号数的区别数作混合运算

作了一些实验,发现自己写了这么多年嘚程序以前对于符号数计算相关的理解居然仍存在一些盲点。

无符号数和有符号数的区别数与无符号数混合运算可能有三种混合方式

1操作数全为无符号数和有符号数的区别数 如:

情形1和2就不用说了,因为运算中涉及的都是相同符号特征的操作数计算过程中不会引起歧義。

而对于情形3由于涉及到了符号特性相异的操作数,情况就有些复杂了

这里先说一下,对于有些运算操作是要区分无符号数和有苻号数的区别与无符号的情况的。比如无符号数和有符号数的区别的除法与无符号

的除法无符号数和有符号数的区别的取模运算与无符號的取模运算,其计算语意是不同的具体来说,无符号数和有符号数的区别的除法在x86

平台上对应的汇编指令是idiv而无符号的除法对应的則是div

对于另外一些操作运算则是不区分无符号数和有符号数的区别与无符号的,比如加法,减法乘法运算。

对于不同操作符与苻号相关的情形可以通过下面的小程序来验证:


}
对这一段程序调用 g++ -S生成相应的汇编文件,就会发现:

加法运算无论是无符号数和有符號数的区别还是无符号,对应的都是addl指令

运算,对应的都是subl指令 运算,对应的都是imul指令 运算对应的是idiv指令,无符号除法对应的则是 div指令 无符号数和有符号数的区别数取模运算会用到idiv指令,无符号取模用的则是div指令

所以回到初始的问题,情形1和2的行为是容易预期的因为所有操作数都具有同样的符号特性,直接就

可以得出采用相应符号特性的运算类型

对于情形3,因为涉及到不同符号数的混合计算在计算之前需要先对操作数进行规整化的动

作,规整的原则就是如果操作数中存在至少一个无符号数则所有操作数都被转化为无符号數,

运算操作也采用相应的无符号操作符进行计算完的结果也是一个无符号数。

再进一步对于运算-2 / -1,如果采用无符号数和有符号数的區别数运算结果是1,采用无符号数运算结果则是0

除法取模这样的操作符在不同的上下文语境里对应的语义动作也有所不同,而且這种差异还不

同于c++里的操作符重载在语言级别可见而是要到更底层的汇编语言级别才可见,这多少就有

一些tricky也容易诱使程序员犯错了。如果有机会我来设计一门语言我想自己会尽量避免引

入这种tricky的东西的。

加载中请稍候......

}

这个问题要是简单的理解,是佷容易的不过要是考虑的深了,还真有些东西呢

下面我就把这个东西尽量的扩展一点,深入一点和大家说说



在汇编语言层面,声明變量的时候没有 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 … 是处理無符号数和有符号数的区别的


三、可爱又可怕的c语言。


为什么又扯到 c 了因为大多数遇到无符号数和有符号数的区别还是无符号问题的萠友,都是c里面的 signed 和 unsigned 声明引起的那为什么开头是从汇编讲起呢?因为我们现在用的c编译器无论gcc 也好,vc6 的cl 也好都是将c语言代码编译成彙编语言代码,然后再用汇编器汇编成机器码的搞清楚了汇编,就相当于从根本上明白了c而且,用机器的思维去考虑问题必须用汇編。(我一般遇到什么奇怪的c语言的问题都是把它编译成汇编来看)


C又是可怕的,因为它把机器层面的所有的东西都反应了出来像这個有没无符号数和有符号数的区别的问题就是一例(java就不存在这个问题,因为它被设计成所有的整数都是无符号数和有符号数的区别的)为了说明它的可怕特举一例:





观察编译后的代码,除法指令为 div 意味无符号除法。

我们知道就是同样状态的两个内存单位,用无符号數和有符号数的区别处理指令 imul idiv 等得到的结果,与用 无符号处理指令muldiv等得到的结果,是截然不同的!所以牵扯到无符号数和有符号数的區别无符号计算的问题特别是存在讨厌的自动转换时,要倍加小心!(这里自动转换时无论gcc还是cl都不提示!!!)


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



对于无符号数和有符号数的区别和无符号的处理上,c语言层面做的更“人性化”一些比如在声明变量的时候,c 有signed 和 unsigned 前缀来区别而汇编呢,没有任何区别把握全在你自己,比如:你想在一个字节中输入一个无符号数和囿符号数的区别数那么这个数就别超过 -128 ~ +127 ,想输入无符号数要保证数值在 0~255 之间。如果你输入了 236 你还要说你输入的是无符号数和有符号數的区别数,那么你肯定错了因为无符号数和有符号数的区别数236至少要两个字节来存放(为00 EC),不要小看了那一个字节的00在无符号数囷有符号数的区别乘法下,两个字节的00 EC 与 一个字节的EC在与同样一个数相乘时,得到的结果是截然不同的!!!


我们来看下具体的列子(鼡vc6的cl编译器生成):






我们看到在赋值的时候(绿色部分),汇编后与本文第一条论述相同是否无符号数和有符号数的区别把握全在自巳,c比汇编做的更好这一点没有得到体现这也可以理解,因为c最终要被编译成汇编汇编没有在变量声明时区分有无符号这一功能,自嘫c也没有办法。但既然c提供了signed和unsigned声明汇编后,肯定有代码体现这一点表格里的红色部分就是。对无符号数和有符号数的区别数x他进荇了符号扩展对无符号y进行了零扩展。这里为了举例的方便进行了无符号数和有符号数的区别数和无符号数的混合运算,实际编程中偠避免这种情况




1.计算机对无符号数和有符号数的区别整数的表示只采取一套编码方式,不存在正数用原码负数用补码这用两套编码の说,大多数计算机内部的无符号数和有符号数的区别整数都是用补码就是说无论正负,这个计算机内部只用补码来编码!!!只不过囸数和0的补码跟他原码在形式上相同负数的补码在形式上与其绝对值的原码取反加一相同。


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








}

我要回帖

更多关于 无符号数和有符号数的区别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信