版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、C51中变量和函数的绝对地址定位问题:1. 变量绝对地址定位 1) 在定义变量时使用 _at_ 关键字加上地址就可. e.g.
2、60; unsigned char idata myvar _at_ 0x40; 把变量 myvar 定义在 idata 的 0x40 处, 在 M51 文件中可以找到这麽一行 &
3、#160; IDATA 0040H 0001H ABSOLUTE 表示有变量在 idata 的 0x0040 处绝对地址定位.
4、 2) 使用 KeilC 编译器定义绝对地址的变量, 方法待查. 2. 函数绝对地址定位 1) 在程序中编写一函数 myTest
5、 void myTest(void) / Add your code here
6、; 2) 使用 KeilC 编译器定位绝对地址的函数, 打开 Project -> Options for Target 菜单, 选中 BL51 Locat
7、e 选项卡, 在 Code: 中输入: ?PR?myTest?MAIN(0x4000) 把函数 myTest 定位到程序区的 0x4000 处,
8、0; 再次编译就可以了. 3) 一次定位多个函数的方法 同样地, 在程序中再编写另外一个函数 myTest1
9、 void myTest1(void) / Add your code he
10、re 在 Options for Target 菜单的 BL51 Locate 选项卡的 Code: 中输入:
11、 ?PR?myTest1?MAIN(0x3900), ?PR?myTest?MAIN(0x4000) 把函数 myTest1 定位在程序区的 0x3900 处, 把函数 myTest 定义在程序区的 0x4000处,
12、0; 重新编译就可以了. 在 M51 文件中可以找到下面的内容: >> 3.obj TO Reader RAMSIZE (256)
13、 CODE (?PR?MYTEST1?MAIN (0X3900), ?PR?MYTEST?MAIN (0X4000) 3665H 029BH
14、; * GAP * CODE 3900H 0014H UNIT ?PR?MYTEST1?MAIN
15、 3914H 06ECH * GAP * &
16、#160; CODE 4000H 0014H UNIT ?PR?MYTEST?MAIN 4) 函数的调用:
17、160; 程序中直接调用函数的方式就不说明了, 这里重点讲使用函数指针调用绝对地址处的函数的方法. (1) 定义调用的函数原形 &
18、#160; typedef void (*CALL_MYTEST)(void); 这是一个回调函数的原形, 参数为空. (2) 定
19、义相应的函数指针变量 CALL_MYTEST myTestCall = NULL; (3) 函数指针变量
20、赋值, 指向我们定位的绝对地址的函数 myTestCall = 0x3900; 指向函数 myTest1
21、 (4) 函数指针调用 if (myTestCall != NULL)
22、0; myTestCall();
23、60; / 调用函数指针处的函数 myTest1, 置 PC 指针为 0x3900
24、160; 检查编译生成的 bin 文件, 到 0x3900 处可以看到 myTest1 的内容, 在 0x4000 处可以看到 myTest 的内容, (5) 其它说明:
25、160; 如果在 0x3000 到 0x3900 的程序空间没有内容时, 把 myTestCall 的地址指针指到0x3800 (在
26、60;0x3000 到 0x3900 之间) 时, 会从 0x3900 处开始执行. 至於在 Load 中调用 AP 中的函数的方法与此类似, 但是相应的参数传递可能要另寻方法. * keil C51绝对地址访问 在利用keil进行8051单片机编程的时,常常需要进行绝对地址进行访问
27、.特别是对硬件操作,如DA AD 采样 ,LCD 液晶操作,打印操作.等等.C51提供了三种访问绝对地址的方法: 1. 绝对宏: 在程序中,用“include<absacc.h>”即可使用其中定义的宏来访问绝对地址,包括: CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD 具体使用可看一看absacc.h便知 例如: rval=CBYTE0x0002;指向程序存贮器的0002h地址 rval=XWORD 0x0002;指向外RA
28、M的0004h地址 2. _at_关键字 直接在数据定义后加上_at_ const即可,但是注意: (1)绝对变量不能被初使化; (2)bit型函数及变量不能用_at_指定。 例如: idata struct link list _at_ 0x40;指定list结构从40h开始。 xdata char text25b _at_0xE000;指定text数组从0E000H开始 提示:如果外部绝对变量是I/O端口等可自行变化数据,需要使用volatile关键字进行描述,请参考absacc.h。 3.
29、;连接定位控制 此法是利用连接控制指令code xdata pdata data bdata对“段”地址进行,如要指定某具体变量地址,则很有局限性,不作详细讨论。 附:(c51)/*- ABSACC.H Direct access to 8051, extended 8051 and Philips 80C51MX memory areas. Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc. All rights reserved. -*/ #ifndef _ABSACC_H_ #def
30、ine _ABSACC_H_ #define CBYTE (unsigned char volatile code *) 0) #define DBYTE (unsigned char volatile data *) 0) #define PBYTE (unsigned char volatile pdata *) 0) #define XBYTE (unsigned char volatile xdata *) 0) #define CWORD (unsigned int volatile code *) 0) #define DWORD (unsigned int volatile da
31、ta *) 0) #define PWORD (unsigned int volatile pdata *) 0) #define XWORD (unsigned int volatile xdata *) 0) #ifdef _CX51_ #define FVAR(object, addr) (*(object volatile far *) (addr) #define FARRAY(object, base) (object volatile far *) (base) #define FCVAR(object, addr) (*(object const far *) (addr) #
32、define FCARRAY(object, base) (object const far *) (base) #else #define FVAR(object, addr) (*(object volatile far *) (addr)+0x10000L) #define FCVAR(object, addr) (*(object const far *) (addr)+0x810000L) #define FARRAY(object, base) (object volatile far *) (base)+0x10000L) #define FCARRAY(object, base
33、) (object const far *) (base)+0x810000L) #endif #endif 附:(c166) /*- ABSACC.H Direct access to 166 memory areas for C166/EC+ Version 5. Copyright (c) 1992-2004 Keil Elektronik GmbH and Keil Software, Inc. All rights reserved. -*/ #ifndef _ABSACC_H_ #define _ABSACC_H_ #if (_MODEL_ = 0) #define MVAR(ob
34、ject, addr) (*(object volatile *) (addr) #define MARRAY(object, base) (object volatile *) (base) #else #define MVAR(object, addr) (*(object volatile far *) (addr) #define MARRAY(object, base) (object volatile far *) (base) #define HVAR(object, addr) (*(object volatile huge *) (addr) #define HARRAY(o
35、bject, base) (object volatile huge *) (base) #define XVAR(object, addr) (*(object volatile xhuge *) (addr) #define XARRAY(object, base) (object volatile xhuge *) (base) #endif #endif 以下来自转载:使用KeilC51软件,可以很方便地将代码或者数据绝对定位到某个地址。1、代码定位:方法1:使用伪指令CSEG。比如要将MyFunc1定位到代码区C:0x1000,则新建一个A51文件,添加以下内容:PUBLI
36、C MYFUNC1CSEG AT 1000HMYFUNC1:;其它代码RET在其它源文件中,就可以调用MyFunc()函数了。需要注意的是,编译器不检测传递参数的数目,仅检测函数是否有返回值。方法2:使用BL51 Locate选项。比如在main.c中定义了一个MyFunc2函数,并且要将该函数定位到代码区C:0x2000,则从菜单中选择Project->Options for Target 'Target1',在弹出的对话框中选择BL51 Locate页,在下面的code栏中写上?PR?MYFUNC2?MAIN(0x2000)即可。如果想定位多个函数,也可以使用*通配符
37、。 2、变量定位:只有全局变量可以绝对定位,局部变量无法实现绝对定位。方法1:使用_at_关键字。声明一个全局变量unsigned char data MyBuf18 _at_ 0x20;方法2:使用BL51 Locate选项。比如将main.c中定义的所有data型的全局变量定位到数据区D:0x28开始的空间,则从菜单中选择Project->Options for Target 'Target1',在弹出的对话框中选择BL51 Locate页,在下面的data栏中写上?DT?MAIN(0x28)即可。如果是idata,则使用?ID?MAIN(0x28),如果是
38、xdata,则使用?XD?MAIN(0x28),如果是pdata,则使用?PD?MAIN(0x28)3、堆栈定位:在STARTUP.A51文件中定义了堆栈区?STACK,其起始地址同样可以在BL51 Locate页中设置,在Stack栏写上?STACK(0x80) BL51 locate 选项卡中code range 和 xdata range如果不填写,编译默认将程序中相应代码和变量从空间前面取起网上看到有人提到在keil中使用_at_进行绝对地址定位问题,我简单介绍一下它的用法。 使用_at_关键字对存储器进行绝对地址定位程序如下i ncl
39、ude<reg51.h>char xdata LED_Data50 _at_ 0x8000;main()LED_Data0 = 0x23;在keil中运行以上程序可以在存储器窗口中输入 x:0x8000 可以看到0x8000地址中的值为0x23.值得指出的几点是1.在给变量LED_Data50定位绝对地址空间时,不能对其赋初值。2.char xdata LED_Data50 _at_ 0x8000;这条语句不能主函数中。有些网友提到在按着keil说明中用_at_进行绝对地址定位时,编译会出现错误274,就是将这条语句放在主函数中的原因。3.keil中地址是自动分
40、配的,所以除非特殊情况否则不提倡使用绝对地址定位。初学者因帖别注意。不要把c当作汇编使用。对需要/RST复位后要保持变量不变,防止意外改变(比如升级到新程序,变量地址可能被编译器优化到其他地方),比较有用!STARTUP.A51 这个文件有什么用,有必要添加到工程吗?如果不添加"startup.a51"文件,编译器就会自动加入一段初始化内存以及堆栈等的代码,这时的内存初始化部分你就无法去控制了,当然这在大部分情况下没什么关系。但是如果你想你的程序在复位后,内存里面的信息依然还保存着(所说的“热复位”),那么你就需要添加该启动文件,并且去里面修改内存初始化部分,不要
41、初始化你需要保留的部分内存。 请问如何在keil编译器里,编程时指定函数的绝对地址 (无内容)不好意思啊,我还从来没有接触过有这样要求情况,不过从网上其他地方找了一篇你参考一下吧,、函数定位:假如要把C源文件 tools.c 中的函数int BIN2HEX(int xx) .放在CODE MEMORY的0x1000处,先编译该工程,然后打开该工程的M51文件,在* * * C O D E M E M O R Y * * *行下找出要定位的函数的名称,应该形如:C
42、ODE xxxxH xxxxH UNIT ?PR?_BCD2HEX?TOOLS然后在:Project->Options for Target .->BL51 Locate:Code中填写如下内容:?PR?_BCD2HEX?TOOLS(0x1000)再次Build,在M51中会发现该函数已放在CODE MEMORY的0x1000处了2、赋初值的变量定位:要将某变量定位在一绝对位置且要赋初值
43、,此时用 _at_ 不能完成,则如下操作:在工程中建立一个新的文件,如InitVars.c,在其中对要处理的变量赋初值(假设是code变量):char code myVer = "COPYRIGHT 2001-11"然后将该文件加入工程,编译,打开M51文件,若定义的是code型,则在* * * C O D E M E M O R Y * * *下可找到:CODE xxxxH xxxxH
44、; UNIT ?CO?INITVARS然后在:Project->Options for Target .->BL51 Locate:Code中填入:?CO?INITVARS(0x200)再次编译即可。相应地,如为xdata变量,则InitVars.c中写:char xdata myVer = "COPYRIGHT 2001-11"然后将该文件加入工程,编译,打开M51文件,在* * * X D A T A M E M O
45、 R Y * * *下可找到:XDATA xxxxH xxxxH UNIT ?XD?INITVARS然后在:Project->Options for Target .->BL51 Locate:Xdata中填入:?XD?INITVARS(0x200)再次编译即可。相应地,若定义的是data/idata等变量,则相应处理即可。3、若有多个变量或函数要进行绝对地址定位,则
46、应按地址从低到高的顺序排列。*PIC 51 混编 C18指定数据绝对地址 51: RSEG是段选择指令,要想明白它的意思就要了解段的意思。段是程序代码或数据对象的存储单位。程序代码放到代码段,数据对象放到数据段。段分两种,一是绝对段,一是再定位段。绝对段在汇编语言中指定,在用L51联接的时候,地址不会改变。用于如访问一个固定存储器的i/o,或提供中断向量的入口地址。而再定位段的地址是浮动的。它的地址有L51对程序模块连接时决定,C51对源程序编译所产生的段都是再定位段,它都有段名和存储类型。绝对段没有段名。说了这么多,大家可能还是不明白段是什么意思。别急
47、,接着往下看。例如,你写用C写了一个函数 void test_fun(void) , 存在test.c中,用编译器编译以后. SRC FILE中看到: ?PR?test_fun?TEST SEGMENT CODE /(函数放到代码段中) 写这个函数体的时候: RSEG ?PR?test_fun?TEST /选择已定位的代码段为当前段 test_fun: /代码所以函数的表达模式是
48、这样: ?PR?函数名?文件名而函数名又分: 1:无参函数 ?PR?函数名?文件名2:有参函数 ?PR?_函数名?文件名3:再入函数 ?PR?_?函数名?文件名又例如 你定义了全局变量 unsigned char data temp1,temp2; unsigned char xdata temp3;在test.c文件中,编译器会为每个文件分0到多个全局数据段,相同类型的全局变量被存到同一段中。所以上面会编译成如下:RSEG ? DT? TEST. temp1: DS 1. temp2: DS 1;RSEG ?XD? TEST. te
49、mp3: DS 1/下面是各个类型的数据全局段的表示?CO? 文件名 /常数段?XD? FILE_NAME /XDATA 数据段?DT? FILE_NAME /DATA 数据段?ID? FILE_NAME /IDATA.?BI? FILE_NAME / BIT .?BA? FILE_NAME /BDATA.?PD? FILE_NAME /PDATA.看到这里大家应该明白段的意思了吧。也许你会问,这有什么作用哪?它就是用在当你需要用汇编语言写一部份程序的时候,把汇编写的函数放在这个问件中,改名xxx.a51,按上面的规则写。编译就好。既然知道了段的意思,现
50、在我们回到SEG的用法上来。A51中有两种段选择指令 : 再定位段选择指令 和 绝对段选择指令. 它们用来选择当前段是再定位段还是绝对段。使用不同的段选择指令,将使程序定位在不同的地址空间之内。 1: 再定位段的选择指令是: RSEG 段名它用来选择一个在前面已经定义过的再定位段作为当前段。用法就像我们上面的例子,先申明了一个函数段,后面写这个函数段。2: 绝对段选择指令CSEG AT 绝对地址表达式 /绝对代码段DSEG AT 绝对地址表达式 /内部绝对数据段XSEG AT
51、 绝对地址表达式 /外部绝对数据段ISEG AT 绝对地址表达式 /内部间接寻址绝对数据段BSEG AT 绝对地址表达式 /绝对位寻址段它们的用法我举一个例子:例如我们写串口中断程序,起始地址是0x23.就这样写CSEG AT 0X23LJMP serialISRRSEG ?PR?serialISR?TEST. serialISR: PIC: 汇编函数使用同一个工程C文件中的变量,例如ICFLAG在C文件中定义,则汇编文件中定义方式为 定义外部变量EXTERN ICFLAG 定义函数 例如CARDATR
52、: . RET GLOBAL CARDATR 在同一个工程文件下调用汇编中的函数CARDATR 则应该定义函数extern void CARDATR(void); C18指定数据绝对地址例如:#pragma udata overlay RECBUFS =0x190 /200UINT8 NUMBER;UINT8 REC_BUF31;#pragma udata *8标签: KEIL C51 编程 KEIL C51高级编程KEIL
53、C51高级编程第一节 绝对地址访问C51提供了三种访问绝对地址的方法:1. 绝对宏:在程序中,用“include”即可使用其中定义的宏来访问绝对地址,包括:CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD具体使用可看一看absacc.h便知例如:rval=CBYTE0x0002;指向程序存贮器的0002h地址rval=XWORD 0x0002;指向外RAM的0004h地址2. _at_关键字直接在数据定义后加上_at_ const即可,但是注意:(1)绝对变量不能被初使化;(2)bit型函数及变量不能用_at_指定。例如:ida
54、ta struct link list _at_ 0x40;指定list结构从40h开始。xdata char text25b _at_0xE000;指定text数组从0E000H开始提示:如果外部绝对变量是I/O端口等可自行变化数据,需要使用volatile关键字进行描述,请参考absacc.h。3. 连接定位控制此法是利用连接控制指令code xdata pdata data bdata对“段”地址进行,如要指定某具体变量地址,则很有局限性,不作详细讨论。第二节 Keil C51与汇编的接口1. 模块内接口方法是用pragma语句具体结构是:#pragma a
55、sm汇编行#pragma endasm这种方法实质是通过asm与ndasm告诉C51编译器中间行不用编译为汇编行,因而在编译控制指令中有SRC以控制将这些不用编译的行存入其中。2. 模块间接口C模块与汇编模块的接口较简单,分别用C51与A51对源文件进行编译,然后用L51将obj文件连接即可,关键问题在于C函数与汇编函数之间的参数传递问题,C51中有两种参数传递方法。(1) 通过寄存器传递函数参数最多只能有3个参数通过寄存器传递,规律如下表:参数数目charintlong,float一般指针123R7R5R3R6 & R7R4 & R5R2 & R3
56、R4R7R4R7R1R3R1R3R1R3(2) 通过固定存储区传递(fixed memory)这种方法将bit型参数传给一个存储段中:?function_name?BIT将其它类型参数均传给下面的段:?function_name?BYTE,且按照预选顺序存放。至于这个固定存储区本身在何处,则由存储模式默认。(3) 函数的返回值函数返回值一律放于寄存器中,有如下规律:return typeRegistev说明bit标志位由具体标志位返回char/unsigned char 1_byte指针R7单字节由R7返回int/unsigned int 2_byte指针R6 &
57、R7双字节由R6和R7返回,MSB在R6long&unsigned long R4R7MSB在R4, LSB在R7floatR4R732Bit IEEE格式一般指针R1R3存储类型在R3 高位R2 低R1(4) SRC控制该控制指令将C文件编译生成汇编文件(.SRC),该汇编文件可改名后,生成汇编.ASM文件,再用A51进行编译。第三节 Keil C51软件包中的通用文件在C51LiB目录下有几个C源文件,这几个C源文件有非常重要的作用,对它们稍事修改,就可以用在自己的专用系统中。1. 动态内存分配init_mem.C:此文件是初始化动
58、态内存区的程序源代码。它可以指定动态内存的位置及大小,只有使用了init_mem( )才可以调回其它函数,诸如malloc calloc,realloc等。calloc.c:此文件是给数组分配内存的源代码,它可以指定单位数据类型及该单元数目。malloc.c:此文件是malloc的源代码,分配一段固定大小的内存。realloc.c:此文件是realloc.c源代码,其功能是调整当前分配动态内存的大小。2. C51启动文件STARTUP.A51启动文件STARTUP.A51中包含目标板启动代码,可在每个project中加入这个文件,只要复位,则该文件立即执行,其功能包括:l 定义内部R
59、AM大小、外部RAM大小、可重入堆栈位置l 清除内部、外部或者以此页为单元的外部存储器l 按存储模式初使化重入堆栈及堆栈指针l 初始化8051硬件堆栈指针l 向main( )函数交权开发人员可修改以下数据从而对系统初始化常数名 意义IDATALEN 待清内部RAM长度XDATA START 指定待清外部RAM起始地址XDATALEN 待清外部RAM长度IBPSTACK 是否小模式重入堆栈指针需初始化标志,1为需要。缺省为0IBPSTACKTOP 指定小模式重入堆栈顶部地址XBPSTACK
60、0;是否大模式重入堆栈指针需初始化标志,缺省为0XBPSTACKTOP 指定大模式重入堆栈顶部地址PBPSTACK 是否Compact重入堆栈指针,需初始化标志,缺省为0PBPSTACKTOP 指定Compact模式重入堆栈顶部地址PPAGEENABLE P2初始化允许开关PPAGE 指定P2值PDATASTART 待清外部RAM页首址PDATALEN 待清外部RAM页长度提示:如果要初始化P2作为紧凑模式高端地址,必须:PPAGEENAGLE1,PPAGE为P2值,例如指定某页1000H10FFH,则PPAGE10H,而且连接时必须
61、如下:L51 PDATA(1080H),其中1080H是1000H10FFH中的任一个值。以下是STARTUP.A51代码片断,红色是经常可能需要修改的地方:;-; This file is part of the C51 Compiler package; Copyright KEIL ELEKTRONIK GmbH 1990;-; STARTUP.A51: This code is executed after processor reset.; To translate this file use A51 with the following invocation:; A51
62、STARTUP.A51; To link the modified STARTUP.OBJ file to your application use the following; L51 invocation:; L51 , STARTUP.OBJ;-; User-defined Power-On Initialization of Memory; With the following EQU statements the initialization of memory; at processor reset can be defined:; ; the absolute start-add
63、ress of IDATA memory is always 0IDATALEN EQU 80H ; the length of IDATA memory in bytes.;XDATASTART EQU 0H ; the absolute start-address of XDATA memoryXDATALEN EQU 0H ; the length of XDATA memory in bytes.;PDATASTART EQU 0H ; the absolute start-address of PDATA memoryPDATALEN EQU 0H ; the length of P
64、DATA memory in bytes.; Notes: The IDATA space overlaps physically the DATA and BIT areas of the; 8051 CPU. At minimum the memory space occupied from the C51; run-time routines must be set to zero.;-; Reentrant Stack Initilization; The following EQU statements define the stack pointer for reentrant;
65、functions and initialized it:; Stack Space for reentrant functions in the SMALL model.IBPSTACK EQU 0 ; set to 1 if small reentrant is used.IBPSTACKTOP EQU 0FFH+1 ; set top of stack to highest location+1.; Stack Space for reentrant functions in the LARGE model.XBPSTACK EQU 0 ; set to 1 if large reent
66、rant is used.XBPSTACKTOP EQU 0FFFFH+1; set top of stack to highest location+1.; Stack Space for reentrant functions in the COMPACT model.PBPSTACK EQU 0 ; set to 1 if compact reentrant is used.PBPSTACKTOP EQU 0FFFFH+1; set top of stack to highest location+1.;-; Page Definition for Using the Compact M
67、odel with 64 KByte xdata RAM; The following EQU statements define the xdata page used for pdata; variables. The EQU PPAGE must conform with the PPAGE control used; in the linker invocation.;PPAGEENABLE EQU 0 ; set to 1 if pdata object are used.PPAGE EQU 0 ; define PPAGE number.;-3. 标准输入输出文件putc
68、har.cputchar.c是一个低级字符输出子程,开发人员可修改后应用到自己的硬件系统上,例如向CLD或LEN输出字符。缺省:putchar.c是向串口输出一个字符XON|XOFF是流控标志,换行符“*n”自动转化为回车/换行“rn”。getkey.cgetkey函数是一个低级字符输入子程,该程序可用到自己硬件系统,如矩阵键盘输入中,缺省时通过串口输入字符。 4. 其它文件还包括对Watch-Dog有独特功能的INIT.A51函数以及对8×C751适用的函数,可参考源代码。第四节 段名协定与程序优化1. 段名协定(Segment Naming
69、 Conventions)C51编译器生成的目标文件存放于许多段中,这些段是代码空间或数据空间的一些单元,一个段可以是可重定位的,也可以是绝对段,每一个可重定位的段都有一个类型和名字,C51段名有以下规定:每个段名包括前缀与模块名两部分,前缀表示存储类型,模块名则是被编译的模块的名字,例如:?CO?main1 :表示main1模块中的代码段中的常数部分?PR?function1?module 表module模块中函数function1的可执行段,具体规定参阅手册。2. 程序优化C51编译器是一个具有优化功能的编译器,它共提供六级优化功能。确保生成目标代码的最高效率
70、(代码最少,运行速度最快)。具体六级优化的内容可参考帮助。在C51中提供以下编译控制指令控制代码优化:OPTIMIZE(SJXE):尽量采用子程序,使程序代码减少。NOAREGS:不使用绝对寄存器访问,程序代码与寄存器段独立。NOREGPARMS:参数传递总是在局部数据段实现,程序代码与低版本C51兼容。OPTIMIZE(SIZE)AK OPTIMIZE(speed)提供6级优化功能,缺省为: OPTIMIZE(6,SPEED)。 第五节 Keil C51的代码效率一、存储模式的影响存储模式决定了缺省变量的存储空间,而访问各空间变量的汇编代码
71、的繁简程度决定了代码率的高低。例如:一个整形变量i,如放于内存18H、19H空间,则+i的操作编译成四条语句:INC 0x19MOV A,0x19JNZ 0x272DINC 0x180x272D:而如果放于外存空间0000H、0001H则+i的操作编译成九条语句:MOV DPTR,0001MOVX A, DPTRINC AMOVX DPTR,AJNz #5MOV OPTR,#0000MOVX A,DPTRINC AMOVX DPTR,A就汇编之后的语句而言,对外部存储器的操作较内部存储器操作代码率要低得多,生成的语句为内存的两倍以上,而程序中有大量的这种操作,可见存储模式对代码率的响了。因此程
72、序设计的原则是1、存储模式从small-Compact-large依次选择,实在是变量太多,才选large模式。2、即使选择了large模式,对一些常用的局部的或者可放于内存中的变量,最好放于内存中,以尽量提高程序的代码率。二、 程序结构的影响程序的结构单元包括模块、函数等等。同样的功能,如果结构越复杂,其所涉及的操作、变量、功能模块函数等就越多,较之结构性好,代码简单的程序其代码率自然就低得多。此外程序的运行控制语句,也是影响代码率的关键因素,例如:switch -case语句,许多编译器都把它们译得非常复杂,Keil C51也不例外,相对较为简易的Switch-case语句,编译
73、成跳转指令形式,代码率较高,但对较为复杂的Switch-Case,则要调用一个系统库函数?C?ICASE进行处理,非常复杂。再如if( ),while( ),等语句也是代码相对较低的语句,但编译以后比switch-case要高得多。因此建议设计者尽量少用switch-case之类语句来控制程序结构,以提高代码率。除以上两点外,其它因素也会对代码率产生影响,例如:是否用寄存器传递参数 即NOAREGS选项是否有是否包括调试信息:即DEBUG选项是否包括扩展的调试信息:即BJECTEXTEND 第六节 如何优化C语言代码(程序员必读)1、选择合适的算法和数据结构应该熟
74、悉算法语言,知道各种算法的优缺点,具体资料请参见相应的参考资料,有很多计算机书籍上都有介绍。将比较慢的顺序查找法用较快的二分查找或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替,都可以大大提高程序执行的效率。.选择一种合适的数据结构也很重要,比如你在一堆随机存放的数中使用了大量的插入和删除指令,那使用链表要快得多。数组与指针语句具有十分密码的关系,一般来说,指针比较灵活简洁,而数组则比较直观,容易理解。对于大部分的编译器,使用指针比使用数组生成的代码更短,执行效率更高。但是在Keil中则相反,使用数组比使用的指针生成的代码更短。2、使用尽量小的数据类型能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变量就不要用长整型(long int),能不使用浮点型(f
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年承德客运从业资格证考试模拟考试
- 吉首大学《妇幼保健学》2021-2022学年第一学期期末试卷
- 吉首大学《企业预算管理》2021-2022学年第一学期期末试卷
- 吉林艺术学院《数字摄影》2021-2022学年第一学期期末试卷
- 店铺砸墙协议书范文范本
- 吉林师范大学《中国思想史》2021-2022学年第一学期期末试卷
- 潮汕生意合作协议书范文范本
- 2022年国家公务员考试《申论》试题真题(行政执法)及答案解析
- 2022年公务员多省联考《申论》真题(广西A卷)及答案解析
- 个人合伙人合同协议书范文模板
- 须弥(短篇小说)
- 旋风除尘器设计与计算
- 《装配基础知识培训》
- 出口退税的具体计算方法及出口报价技巧
- PCB镀层与SMT焊接
- Unit 1 This is my new friend. Lesson 5 课件
- 2019年青年英才培养计划项目申报表
- 剪纸教学课件53489.ppt
- 芳香油的提取
- 劳动法讲解PPT-定稿..完整版
- 企业人才测评发展中心建设方案
评论
0/150
提交评论