C数据类型转换及操作

上传人:cn****1 文档编号:455338042 上传时间:2022-10-10 格式:DOCX 页数:11 大小:24.77KB
返回 下载 相关 举报
C数据类型转换及操作_第1页
第1页 / 共11页
C数据类型转换及操作_第2页
第2页 / 共11页
C数据类型转换及操作_第3页
第3页 / 共11页
C数据类型转换及操作_第4页
第4页 / 共11页
C数据类型转换及操作_第5页
第5页 / 共11页
点击查看更多>>
资源描述

《C数据类型转换及操作》由会员分享,可在线阅读,更多相关《C数据类型转换及操作(11页珍藏版)》请在金锄头文库上搜索。

1、void foo(void)unsigned int a = 6;int b = -20;(a+b 6) puts( 6) : puts(6”。原因是当表达式中存在有符号类型和 无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常 大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符 号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到 了得不到这份工作的边缘在汇编语言层面,声明变量的时候,没有 signed 和 unsignde 之分,汇编器统 统,将你输入的整数字面量当作有符号数处理成补码存入到计算机中,只有这一 个标准!汇编器不会区

2、分有符号还是无符号然后用两个标准来处理,它统统当作 有符号的!并且统统汇编成补码!也就是说,db -20汇编后为:EC,而db 236 汇编后也为 EC 。这里有一个小问题,思考深入的朋友会发现, db 是分配一个 字节,那么一个字节能表示的有符号整数范围是: -128 +127 ,那么 db 236 超 过了这一范围,怎么可以?是的, +236 的补码的确超出了一个字节的表示范围, 那么拿两个字节(当然更多的字节更好了)是可以装下的,应为:00 EC,也就 是说+236的补码应该是00 EC,一个字节装不下,但是,别忘了“截断”这个概念, 就是说最后汇编的结果被截断了, 00 EC 是两个字

3、节,被截断成 EC ,所以, 这是个“美丽的错误”,为什么这么说?因为,当你把 236 当作无符号数时,它 汇编后的结果正好也是 EC ,这下皆大欢喜了,虽然汇编器只用一个标准来处 理,但是借用了“截断”这个美丽的错误后,得到的结果是符合两个标准的!也就 是说,给你一个字节,你想输入有符号的数,比如 -20 那么汇编后的结果是符 合有符号数的;如果你输入 236 那么你肯定当作无符号数来处理了(因为 236 不在一个字节能表示的有符号数的范围内啊),得到的结果是符合无符号数的。 于是给大家一个错觉:汇编器有两套标准,会区分有符号和无符号,然后分别汇 编。其实,你们被骗了。 :-)3.第一点说明

4、汇编器只用一个方法把整数字面量汇编成真正的机器数。但并不是 说计算机不区分有符号数和无符号数,相反,计算机对有符号和无符号数区分的 十分清晰,因为计算机进行某些同样功能的处理时有两套指令作为后备,这就是 分别为有符号和无符号数准备的。但是,这里要强调一点,一个数到底是有符号 数还是无符号数,计算机并不知道,这是由你来决定的,当你认为你要处理的数 是有符号的,那么你就用那一套处理有符号数的指令,当你认为你要处理的数是 无符号的,那就用处理无符号数的那一套指令。加减法只有一套指令,因为这一 套指令同时适用于有符号和无符号。下面这些指令: mul div movzx 是处理无 符号数的,而这些: i

5、mul idiv movsx 是处理有符号的。举例来说:内存里有一个字节x为:Ox EC,一个字节y为:Ox 02。当把x, y当作有符 号数来看时, x = -20 , y = +2 。当作无符号数看时, x = 236 , y = 2 。下面进 行加运算,用add指令,得到的结果为:Ox EE,那么这个Ox EE当作有符号 数就是:-18 ,无符号数就是 238 。所以, add 一个指令可以适用有符号和无 符号两种情况。(呵呵,其实为什么要补码啊,就是为了这个呗, :-) 乘法运算就不行了,必须用两套指令,有符号的情况下用 imul 得到的结果是: Ox FF D8 就是 -4O 。无符

6、号的情况下用 mul ,得到: Ox O1 D8 就是 472 。4为什么又扯到c 了?因为大多数遇到有符号还是无符号问题的朋友,都是c里 面的 signed 和 unsigned 声明引起的,那为什么开头是从汇编讲起呢?因为我 们现在用的c编译器,无论gcc也好,vc6的cl也好,都是将c语言代码编译成汇 编语言代码,然后再用汇编器汇编成机器码的。搞清楚了汇编,就相当于从根本 上明白了c,而且,用机器的思维去考虑问题,必须用汇编。(我一般遇到什么奇 怪的c语言的问题都是把它编译成汇编来看。)C是可爱的,因为c符合kiss原则,对机器的抽象程度刚刚好,让我们即提高了 思维层面(比汇编的机器层面

7、人性化多了),又不至于离机器太远(像c#,java 之类就太远了)。当初K&R版的c就是高级一点的汇编,C又是可怕的,因为它把 机器层面的所有的东西都反应了出来,像这个有没有符号的问题就是一例(java 就不存在这个问题,因为它被设计成所有的整数都是有符号的)。为了说明它的 可怕特举一例:#include vstdio.h#include vstring.hint main()int x = 2;char * str = abcd;int y = (x - strlen(str) ) / 2;printf(%dn,y);结果应该是-1但是却得到:2147483647。为什么?因为strlen的

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

9、时,要倍加小心 为了避免这些错误,建议,凡是在运算的时候,确保你的变量都是 signed 的。 定义 INT16S ltr1 = 0;ltr1 +;if(ltr1 = = 32767)ltr1 += 1;ltr1 += 2;当ltrl等于32767时,到了有符号整数的最大值,加1就是-32768 (0X8000) 再加2就是-32766(0X8002)6. INT16U i;INT16S *k;INT32S mbx;k = pmes + 7;mbx=0;for(i=0;iCOUNTOFCALSAMP;i+) /*32*4计算的周波*/mbx += *k;k +=NUMOFCAL;/*存放的是8

10、个量*/ltr = labs(mbx); /整型量的值有可能出现负值时,当需要提取负值时需要用 labs取绝对值来反映其实际大小。ltr = (INT16U)(mbx); 整型量的值有可能出现负值时,当mbx = - 6时,即 mbx = 0xfffffffa这种强制转换并不能得到我们想要的值,相反它的结果很大,是 fffa。7. INT16S ltr1;INT16U ltr2, ltr3;INT8U a;INT16S b;a= 6;b = -20;ltr1 = a + b;ltr2 = (INT16S)(a + b);c = 5;d = 15;ltr3 = c - d;/这个值会得到5到15

11、之间的距离。结果是:ltr1 = -14 ltr2 = 65522 ltr3 = 65526 当一个整型变量赋值给一个无符号的整型时,数据格式不变,直接复制。ltr1 本身是整型, ltr1 = a + b = 0xfff2 = - 14;Ltr2本身是无符号整型,ltr2 = (INT16S)(a + b) 0xfff2 =65522 ;可见它们的16进制 数值是一样的,这取决于赋值号左边的数据类型,这个法则只适合加减运算。 Ltr3当它是无符号整型时,值为65526(0xfff6),当它为整型时,值为-10(0xfff6); 其16进制表示是一致的,区别是要看赋值号左边的数据类型。这个法则

12、只适合加 减运算总结:1.当运算符两边一个是有符号整型,一个是无符号整型时,有符号整型转成 无符号整型 ,然后再运算。这样问题就来了,当运算结果赋值给整型时是没有问题的,当运算结果赋值 给无符号整型时,问题就有了,结果为负值的时候将得到一个很大数值,这个值 用于运算时会出错。可见,整型量与无符号整型在16进制的写法上没有什么区别,当整型量的负 数部分从bllll 1111 1111 111表示-1, blOOO 0000 0000 0000表示-32768,这样的 好处是便于加减法运算,可以将减法运算转变为加法运算,如 7 - 3 = 4,将3变 为补码为:b1111111111111101

13、+ blll = b100可见这是一种技法。8. INT8U a;INT16S b;INT16S ltr1;INT16S ltr1;INT16S acqbuf256;b = -12368;a = acqbuf222;ltr1 = b/a;Ltr2 = b/a;当acqbuf222 = 30时,ltrl = 1772, ltr2 = 1772而不是我们要得到的负值。因 为变量a是无符号整型,变量b的补码形式0xcfb0,运算时编译器将变量b当作无 符号整型来运算,将最高位认为是数据,而不是符号,使用I$UDIV函数来运算, 即 0xcfb0 / 30 = 1772如果这样写ltrl = b/ac

14、qbuf222 = -412 ;就对了,因为他们都是整型量,编译 器使用I$DI V函数来运算,将最高位认为是符号位。INT16U ltr1;INT16S ltr2;INT16S b;INT16S acqbuf256;b = -6;ltrl = -6;ltr 1是无符号整型 所有ltrl = 65530ltr2 = acqbuf224/b; 都为整型,且负数除以负数等于正数,所有ltr2 = 1。10 INT16S ltr1;INT16S ltr2;INT8U a,c,d;INT16S b;INT16S acqbuf256;a = 635;b = -635;ltr1 = b/acqbuf222

15、; /acqbuf222 = 29时, ltr1 = -21。ltr2 = a/acqbuf224;acqbuf224 = -6时,ltr2 = 0。11.INT16S ltr1;INT16S ltr2;INT16U ltr3;INT16S acqbuf256;ltr1 = acqbuf222/-2;/acqbuf222 =30时,ltr1 = -15。ltr2 = acqbuf224/2;/acqbuf224 =-7时,ltr2 = -3。ltr3 = acqbuf224/2;/acqbuf224 =-7时,ltr2 = 0xfffd =65533。以上除法编译的汇编语言中调用有符号的除法指令,I$DIV函数。 再次总结:混合运算时,加减乘除的表达式中,运算符两边一个是有符号整型,一个是 无符号整型时,有符号整型转成无符号整型 ,然后再运算。二进制运算以补码形式进行,不管加减乘除都会转化为这个形式,补码的好 处就是将减法运算变为加法运算,这样的好处是可以省去硬件的减法电路。这样

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 机械/制造/汽车 > 电气技术

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号