最近单片机课讲到了定时计数器,在C语言中定时计数器的初值可以采用这种方式(假设计数10000次)TH0=(65536-10000)/256;TL0=(65536-10000)%6;这是通用的方法,65536-10000=55536=0xD8F0;赋值后TH0=0xD8,TL0=0xF0。我联想到补码的规则,65536-10000的数值在计算机中和-10000数据存储是一样的,于是我就简单赋值为TH0=(-10000)/256.;TL0=(-10000)%6;可以少写一个数据,减少敲字的工作。我就这样给学生讲了。这两种方法都可以。

在一天李老师看到我的学生作业都是写TH0=(-10000)/256.;TL0=(-10000)%6;她说-10000可能使用不对。当天晚上的时候在QQ上发消息过来说,经验证,在Keil中,TH0=(65536-10000)/256;TL0=(65536-10000)%6;的赋值方式TH0=0xD8,TL0=0xF0。但是TH0=(-10000)/256.;TL0=(-10000)%6;的赋值方式TH0=0xD9,TL0=0xF0。TH0的数值总是要大1,而且取不同的数值验证均是这个结果,两种方式TH0总是相差1,而TL0数值是一样的。我打开Keil,输入程序,然后调试查看汇编指令,得到如下结果:

8: TH0=(65536-10000)/256;
C:0x009B    758CD8   MOV      TH0(0x8C),#0xD8
     9:   TH1=(-10000)/256;
C:0x009E    758DD9   MOV      TH1(0x8D),#0xD9

发现汇编指令直接对于TH0和TH1进行赋值,没有经过任何的运算,但是就是相差1,这是为什么呢?我无法理解,后来在百度知道上提问,得到的回答是:这个和默认数据类型有关,TH0=(65536-10000)/256,默认unsigned char,即TH0=0xD8;TH0=(-10000)/256,默认signed char,二进制最高位为符号位,负数为1,所以TH0=0xD9 。

原来是Keil编译器计算数据的时候默认的数据类型不一样,65536-10000=55536是unsigned类型,55536/256=216=0xD8,而-10000是signed类型,(-10000)/256=-39=0xD9。原来如此,Keil的编译器预先处理的时候根据不同类型的数据进行了不同的运算,然后直接赋值。我又验证了一下,TH0=(unsigned int)(-10000)/256;发现先把-10000强制转换为unsigned类型后,得到的结果就是正确的了TH0=0xD8。得到答案后脸红了,不过多亏是在放假期间,没有学生看到。开学后立即在课堂上更正了。╮(╯▽╰)╭,这次糗大了。

我重新写了一个程序,#include<reg51.h>
void main()
{
unsigned int  i;
 unsigned char j;
 i= - 10000;
 j=i/256;

while(1)
 ;
}

中间加一个变量,看Keil会怎么处理,结果发现

2: void main()
     3: { 
     4: unsigned int  i;
     5:  unsigned char j;
     6:  i=-10000;
C:0x000F    7ED8     MOV      R6,#0xD8
     7:  j=i/256;
     8: 
C:0x0011    8E08     MOV      0x08,R6
     9: while(1)
C:0x0013    80FE     SJMP     C:0013

还是直接赋值,编译器太聪明了,知道80C51对于数据运算非常非常的不擅长,于是直接处理完数据,然后用赋值的方式来写汇编的指令。而且还知道,i的低字节没有用到,在指令里根本没有出现,这也太聪明了吧。Keil软件是最流行,最好用的编译器,不是浪得虚名的。

我再修改:

include<reg51.h>
void main()
{
unsigned int  i;
 unsigned char j;
 i=-10000;
 i++;
 j=i/256;

while(1)
 ;
}

结果发现代码只增加了一点。

2: void main()
     3: { 
     4: unsigned int  i;
     5:  unsigned char j;
     6:  i=-10000;
C:0x0003    7FF0     MOV      R7,#B(0xF0)
C:0x0005    7ED8     MOV      R6,#0xD8
     7:  i++;
C:0x0007    0F       INC      R7
C:0x0008    BF0001   CJNE     R7,#0x00,C:000C
C:0x000B    0E       INC      R6
     8:  j=i/256;
     9: 
C:0x000C    8E08     MOV      0x08,R6
    10: while(1)
C:0x000E    80FE     SJMP     C:000E

但对于j的运算还是用赋值的方式。我再改,把i类型变成signed类型,结果大吃一惊:

include<reg51.h>
void main()
{
    int  i;
 unsigned char j;
 i=-10000;
 
 j=i/256;

while(1)
 ;
}

程序变得非常庞大,代码从28B猛增到169B:

C:0x0000 02009D LJMP C:009D C?SIDIV: C:0x0003 C2D5 CLR F0(0xD0.5) C:0x0005 EC MOV A,R4 C:0x0006 30E709 JNB 0xE0.7,C:0012 C:0x0009 B2D5 CPL F0(0xD0.5) C:0x000B E4 CLR A C:0x000C C3 CLR C C:0x000D 9D SUBB A,R5 C:0x000E FD MOV R5,A C:0x000F E4 CLR A C:0x0010 9C SUBB A,R4 C:0x0011 FC MOV R4,A C:0x0012 EE MOV A,R6 C:0x0013 30E715 JNB 0xE0.7,C:002B C:0x0016 B2D5 CPL F0(0xD0.5) C:0x0018 E4 CLR A C:0x0019 C3 CLR C C:0x001A 9F SUBB A,R7 C:0x001B FF MOV R7,A C:0x001C E4 CLR A C:0x001D 9E SUBB A,R6 C:0x001E FE MOV R6,A C:0x001F 120039 LCALL C?UIDIV(C:0039) C:0x0022 C3 CLR C C:0x0023 E4 CLR A C:0x0024 9D SUBB A,R5 C:0x0025 FD MOV R5,A C:0x0026 E4 CLR A C:0x0027 9C SUBB A,R4 C:0x0028 FC MOV R4,A C:0x0029 8003 SJMP C:002E C:0x002B 120039 LCALL C?UIDIV(C:0039) C:0x002E 30D507 JNB F0(0xD0.5),C:0038 C:0x0031 C3 CLR C C:0x0032 E4 CLR A C:0x0033 9F SUBB A,R7 C:0x0034 FF MOV R7,A C:0x0035 E4 CLR A C:0x0036 9E SUBB A,R6 C:0x0037 FE MOV R6,A C:0x0038 22 RET C?UIDIV: C:0x0039 BC000B CJNE R4,#0x00,C:0047 C:0x003C BE0029 CJNE R6,#0x00,C:0068 C:0x003F EF MOV A,R7 C:0x0040 8DF0 MOV B(0xF0),R5 C:0x0042 84 DIV AB C:0x0043 FF MOV R7,A C:0x0044 ADF0 MOV R5,B(0xF0) C:0x0046 22 RET C:0x0047 E4 CLR A C:0x0048 CC XCH A,R4 C:0x0049 F8 MOV R0,A C:0x004A 75F008 MOV B(0xF0),#0x08 C:0x004D EF MOV A,R7 C:0x004E 2F ADD A,R7 C:0x004F FF MOV R7,A C:0x0050 EE MOV A,R6 C:0x0051 33 RLC A C:0x0052 FE MOV R6,A C:0x0053 EC MOV A,R4 C:0x0054 33 RLC A C:0x0055 FC MOV R4,A C:0x0056 EE MOV A,R6 C:0x0057 9D SUBB A,R5 C:0x0058 EC MOV A,R4 C:0x0059 98 SUBB A,R0 C:0x005A 4005 JC C:0061 C:0x005C FC MOV R4,A C:0x005D EE MOV A,R6 C:0x005E 9D SUBB A,R5 C:0x005F FE MOV R6,A C:0x0060 0F INC R7 C:0x0061 D5F0E9 DJNZ B(0xF0),C:004D C:0x0064 E4 CLR A C:0x0065 CE XCH A,R6 C:0x0066 FD MOV R5,A C:0x0067 22 RET C:0x0068 ED MOV A,R5 C:0x0069 F8 MOV R0,A C:0x006A F5F0 MOV B(0xF0),A C:0x006C EE MOV A,R6 C:0x006D 84 DIV AB C:0x006E 20D21C JB OV(0xD0.2),C:008D C:0x0071 FE MOV R6,A C:0x0072 ADF0 MOV R5,B(0xF0) C:0x0074 75F008 MOV B(0xF0),#0x08 C:0x0077 EF MOV A,R7 C:0x0078 2F ADD A,R7 C:0x0079 FF MOV R7,A C:0x007A ED MOV A,R5 C:0x007B 33 RLC A C:0x007C FD MOV R5,A C:0x007D 4007 JC C:0086 C:0x007F 98 SUBB A,R0 C:0x0080 5006 JNC C:0088 C:0x0082 D5F0F2 DJNZ B(0xF0),C:0077 C:0x0085 22 RET C:0x0086 C3 CLR C C:0x0087 98 SUBB A,R0 C:0x0088 FD MOV R5,A C:0x0089 0F INC R7 C:0x008A D5F0EA DJNZ B(0xF0),C:0077 C:0x008D 22 RET

2: void main()
     3: { 
     4:     int  i;
     5:  unsigned char j;
     6:  i=-10000;
     7:  
C:0x008E    7FF0     MOV      R7,#B(0xF0)
C:0x0090    7ED8     MOV      R6,#0xD8
     8:  j=i/256;
     9: 
C:0x0092    7C01     MOV      R4,#0x01
C:0x0094    7D00     MOV      R5,#0x00
C:0x0096    120003   LCALL    C?SIDIV(C:0003)
C:0x0099    8F08     MOV      0x08,R7
    10: while(1)
C:0x009B    80FE     SJMP     C:009B

就是一个signed和unsigned的区别,用的着差别这么大吗?

通过以上的实验,可以得出结论:Keil编译器非常智能,会生成最短的代码,能够智能判断每个变量的使用,生成最短的代码。同时,学习单片机的各位同仁,除非万不得已,千万不要用signed类型。

单片机中无符号和有符号变量使用相关推荐

  1. c语言无符号中符号什么意思,C语言中无符号与有符号及相加问题

    C语言中无符号与有符号问题 unsigned char a[5] = { 12,36,96,128,182 }; a[]范围为0~256. 数组中数都有效. char a[5] = { 12,36,9 ...

  2. c语言中 加法符号如何定义,【 c语言中无符号和有符号的加法运算】【深入理解】--【sky原创】...

    第一题 #include int main() { unsigned int a=6; int b=-20; printf("%d\n",a+b); (a+b)>6? put ...

  3. C语言中的强符号与弱符号(关于变量声明与定义的深入讨论)

    看到一篇介绍C语言强符号与弱符号的文章非常好,转载过来加深印象. 原文地址:http://blog.csdn.net/astrotycoon/article/details/8008629 ===== ...

  4. java 无符号转有符号_java有符号无符号的转换

    数据处理中常常遇到基本数据类型的操作,java都是有符号的数据,而与下位机通信中常常遇到无符号的比如uint8, uint16,uint32等等 1.为了完成这个功能还专门采用ByteBuffer的方 ...

  5. 如何用matlab中syms建立符号方程,用matlab求解符号方程及符号方程组

    符号方程的求解 MATLAB7.0中的符号计算可以求解线性方程(组).代数方程的符号解.非线性符号方程(组).常微分方程(组),求解这些方程(组)是通过调用solve函数实现的,如求解代数方程的符号解 ...

  6. 无符号与有符号类型转换和值为负数情况

    1. 我们知道,当一个整型变量为有符号时,一般不管是赋正数还是负数,只要赋的值不超过该变量类型所表示的范围,值是不会变的. 2. 但当给无符号整形变量赋予负数值时,该变量会发生180度的变化.比如给一 ...

  7. c语言弱符号与函数指针,浅谈C语言中的强符号、弱符号、强引用和弱引用【转】...

    首先我表示很悲剧,在看<程序员的自我修养--链接.装载与库>之前我竟不知道C有强符号.弱符号.强引用和弱引用.在看到3.5.5节弱符号和强符号时,我感觉有些困惑,所以写下此篇,希望能和同样 ...

  8. java中3.14是什么符号_java中3.14f是什么意思 C++问题下列选项中属

    这个是浮点型数据的表示方法. 在定义变量,给变量赋值的时候,float类型后面可以跟一个f来表示这个数值是浮点型的. double类型的数据后面可以跟一个d表示数值是double类型(双精度类型)的. ...

  9. 【嵌入式基础小知识】详解单片机中的程序和变量是如何分布的以及一些注意事项

    "我固然不是了不起的跑步者,而是处于极为平凡的--毋宁说是凡庸的--水准.然而这个问题根本不重要.我超越了昨天的自己,哪怕只是那么一丁点儿,才更为重要.在长跑中,如果说有什么必须战胜的对手, ...

最新文章

  1. 【百度地图API】北京周边7日游——图标按路线轨迹行动
  2. php笔记之表单验证
  3. math.floor java_Java Math.floor() 方法
  4. 使用I/O 系统调用--copy.c
  5. 第四章语法分析和语法分析程序
  6. 【sampleDateFormat】对日期进行解析
  7. Android基于WIFI实现电脑和手机间数据传输的技术方案研究
  8. Win11 PE下如何快速设置IP如何新建共享文件夹并设置为everyone完全控制权限
  9. OpenCV+ip摄像头实现远程实时监控
  10. 分销APP联盟商家入驻商城系统开发
  11. 图片去水印接口,模糊图片中水印
  12. 在php中 var什么意思,php关键字”var”的作用是什么?
  13. mysql 匹配多个字符_在MySQL语句中,可以匹配0个到多个字符的通配符是____。
  14. http状态码301和302详解及区别——辛酸的探索之路
  15. php rot13解密,用PHP实现ROT13
  16. NOI题库答案(1.5 编程基础之循环控制)(21—45题)
  17. 动态规划求解TSP(旅行商)问题
  18. ITF-14条形码外框如何设置
  19. 用python打开视频_MoviePy - 用Python玩转视频剪辑!(MoviePy安装及视频文件读取)...
  20. 浅谈BIM在消防安全管理方面的优势

热门文章

  1. 谷歌无人车开创者敲钟上市!平台型自动驾驶第一股市值130亿美元
  2. python进行聚类分析:鸢尾花(iris)代码
  3. http://www.cnblogs.com/hoojo/archive/2011/06/08/2075201.html
  4. 富裕的深圳人与租房的深圳人
  5. 静态内部类和访问非静态成员变量
  6. TCHAR 宽字节的sprintf
  7. 制定量化策略必须考虑的事情
  8. Kafka Producer幂等性
  9. 纷争终结者: 被遗弃的孩子们 TROUBLESHOOTER: Abandoned Children V20230206+DLC最新中文学习版 单机游戏 游戏下载【8.1G】
  10. 国内外主流商业智能(BI)软件介绍及点评