OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5041|回复: 4

关于51-Keil编译器对16bit数据比较问题

[复制链接]

2

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2015-5-26
在线时间
5 小时
发表于 2015-5-26 09:46:23 | 显示全部楼层 |阅读模式
5金钱
我遇到这么一个问题,觉得像是Keil的一个bug!问题描述如下:
51单片机是8bitMCU,没有操作16bit数据的指令,如果要将两个16bit的数据比较大小,Keil编译器会对其使用一个算法进行比较。
下面是16bit数据比较的C语言代码:
[mw_shl_code=c,true]/* IDE-Version: ?Vision V5.11.2.0 Copyright (C) 2014 ARM Ltd and ARM Germany GmbH. All rights reserved. Tool Version Numbers: Toolchain: PK51 Prof. Developers Kit Version: 9.53.0.0 Toolchain Path: D:\Keil_v5\C51\BIN C Compiler: C51.exe V9.53.0.0 Assembler: A51.exe V8.02b Linker/Locator: BL51.exe V6.22 Librarian: LIB51.exe V4.30.0.2 Hex Converter: OH51.exe V2.7.0.0 CPU DLL: S8051.DLL V3.95.0.0 Dialog DLL: DP51.DLL V2.62.0.1 Target DLL: STCMON51.DLL V1, 0, 3, 0 Dialog DLL: TP51.DLL V2.58 */ sbit CY = 0xD7; main() { unsigned char xdata data1_L=0x03; unsigned char xdata data1_H=0x6A; unsigned char xdata data2_L=0x0A; unsigned char xdata data2_H=0x7A; unsigned char xdata tmp=5; while(1) { if(((data1_H<<8)+data1_L) <= ((data2_H<<8)+data2_L)) { tmp++; } } }[/mw_shl_code]
这段C语言16bit数据比较部分的汇编代码如下:
[mw_shl_code=c,true]0014 900000 R MOV DPTR,#data2_H 0017 E0 MOVX A,@DPTR 0018 FE MOV R6,A 0019 900000 R MOV DPTR,#data2_L 001C E0 MOVX A,@DPTR 001D 7C00 MOV R4,#00H 001F 2400 ADD A,#00H 0021 FD MOV R5,A 0022 EC MOV A,R4 0023 3E ADDC A,R6 0024 FC MOV R4,A 0025 900000 R MOV DPTR,#data1_H 0028 E0 MOVX A,@DPTR 0029 FE MOV R6,A 002A 900000 R MOV DPTR,#data1_L 002D E0 MOVX A,@DPTR 002E 7A00 MOV R2,#00H 0030 2400 ADD A,#00H 0032 FF MOV R7,A 0033 EA MOV A,R2 0034 3E ADDC A,R6 0035 FE MOV R6,A 0036 D3 SETB C 0037 EF MOV A,R7 0038 9D SUBB A,R5 0039 EC MOV A,R4 003A 6480 XRL A,#080H 003C F8 MOV R0,A 003D EE MOV A,R6 003E 6480 XRL A,#080H 0040 98 SUBB A,R0 0041 50D1 JNC ?C0001[/mw_shl_code]
这个比较是成立的,tmp变量实现了加1。但是当比较值为如下的时候:
第二组数据:
[mw_shl_code=c,true]unsigned char xdata data1_L=0x03; unsigned char xdata data1_H=0x6A; unsigned char xdata data2_L=0x0A; unsigned char xdata data2_H=0xFA;[/mw_shl_code]

C代码中的比较语句是不成的,也就是说,tmp没有加1。那段汇编代码的大意就是:
data1的LSB减去data2的LSB,标记借位CY。data1的MSB减去data2的MSB减去上一次减法的借位CY。
如果当前借位CY为0证明data1>=data2,CY为1证明data1<data2。
那么问题来了,
汇编代码中最后的两次异或运算有何用意?这两次异或运算直接导致第二组数据判断结果不正确!

最佳答案

查看完整内容[请看2#楼]

问题已解决。这不是Keil的bug,详细原因如下: 对于移位操作符 << 或者 >>,这是双目操作符,有两个操作数。在C标准中规定,移位时被移位数(左操作数)有个类型转换,规则如下: 如果左操作数当前类型的有符号数范围小于高于其类型一级(int > short > char)的有符号数的范围,那么操作数当前类型的无符号数会转换为高一级类型的有符号数。在这里就是,unsigned char类型的数据左移8位,类型转换为short类型,然后 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2015-5-26
在线时间
5 小时
 楼主| 发表于 2015-5-26 09:46:24 | 显示全部楼层
问题已解决。这不是Keil的bug,详细原因如下:
对于移位操作符 << 或者 >>,这是双目操作符,有两个操作数。在C标准中规定,移位时被移位数(左操作数)有个类型转换,规则如下:
如果左操作数当前类型的有符号数范围小于高于其类型一级(int > short > char的有符号数的范围,那么操作数当前类型的无符号数会转换为高一级类型的有符号数。在这里就是,unsigned char类型的数据左移8位,类型转换为short类型,然后unsigned char类型的数据再加short类型的数据,最终结果就是一个有符号的short类型的数据。这也就解释了最初那段C的汇编在比较MSB时,对其进行异或运算。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165353
金钱
165353
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-5-27 01:10:36 | 显示全部楼层
帮顶。。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

2

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2015-5-26
在线时间
5 小时
 楼主| 发表于 2015-5-27 09:20:09 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
受宠若惊( ⊙ o ⊙ )
回复

使用道具 举报

2

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2015-5-26
在线时间
5 小时
 楼主| 发表于 2015-5-27 09:29:14 | 显示全部楼层
补充:
同样的环境,当C语言的写如下的时候
[mw_shl_code=c,true]unsigned short xdata data1 = 0x6A0A; unsigned short xdata data2 = 0xFA03; if(data1 <= data2) { tmp++; }[/mw_shl_code]
不论何种数据组合,比较结果都是正确的。他的汇编代码如下:
[mw_shl_code=c,true]0059 900000 R MOV DPTR,#data2 005C E0 MOVX A,@DPTR 005D FE MOV R6,A 005E A3 INC DPTR 005F E0 MOVX A,@DPTR 0060 FF MOV R7,A 0061 D3 SETB C 0062 900000 R MOV DPTR,#data1+01H 0065 E0 MOVX A,@DPTR 0066 9F SUBB A,R7 0067 900000 R MOV DPTR,#data1 006A E0 MOVX A,@DPTR 006B 9E SUBB A,R6 006C 50BB JNC ?C0001[/mw_shl_code]
这段汇编的大意和之前的一样,不过少了最后的两个异或运算。
之前的C语言写法,会导致某些数据的比较出错,不知是编译器的bug还是编译器有啥特别的想法。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-26 22:05

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表