Keil C51中函数指针使用注意事项
c51指针用法
c51指针用法
C51是一种常用的单片机,使用指针可以更灵活地操作内存和外设。
在C51中,指针可以用于访问和操作内存中的数据,也可以用于操作外设寄存器。
首先,我们可以使用指针来访问和操作内存中的数据。
在C51中,内存被分为不同的存储区域,如代码区、数据区和堆栈区。
通过使用指针,我们可以直接访问和修改这些存储区域中的数据。
例如,我们可以使用指针来读取和修改数组中的元素,而不需要使用数组索引。
这种方法可以提高程序的执行效率。
其次,指针还可以用于操作外设寄存器。
在单片机编程中,外设寄存器用于控制和配置外部设备,如GPIO(通用输入输出)、定时器和串口等。
通过使用指针,我们可以直接访问和修改这些寄存器的值,从而控制外部设备的行为。
例如,我们可以使用指针来设置GPIO引脚的状态,或者配置定时器的工作模式。
除了访问和操作内存和外设寄存器,指针还可以用于动态内存分配和数据结构的操作。
在C51中,我们可以使用指针来动态分配内存,并在运行时根据需要分配和释放内存。
这种灵活的内存管理方式可以提高程序的效率和灵活性。
此外,指针还可以用于创建和操作复杂的数据结构,如链表和树等。
通过使用指针,我们可以方便地插入、删除
和修改数据结构中的元素。
总之,C51中的指针用法非常重要,可以帮助我们更灵活地操作内存和外设。
通过使用指针,我们可以提高程序的执行效率,实现动态内存分配,以及创建和操作复杂的数据结构。
因此,熟练掌握C51指针的用法对于单片机编程非常重要。
C51 指针问题
C51 指针问题一般指针一般指针的声明和使用均与标准C 相同,不过同时还可以说明指针的存储类型,例如:long * state;为一个指向long 型整数的指针,而state 本身则依存储模式存放。
char * xdata ptr;ptr 为一个指向char 数据的指针,而ptr本身放于外部RAM 区,以上的long,char 等指针指向的数据可存放于任何存储器中。
一般指针本身用3 个字节存放,分别为存储器类型,高位偏移,低位偏移量。
2.存储器指针基于存储器的指针说明时即指定了存贮类型,例如:chardata * str;str 指向data 区中char 型数据int xdata * pow; pow 指向外部RAM 的int 型整数。
这种指针存放时,只需一个字节或2 个字节就够了,因为只需存放偏移量。
/*.........................................................................................char * xdata ptr;//ptr 本身放在Xdata(XRAM)区char xdata * ptr;//ptr 指向的数据放在Xdata(XRAM)区........................................................................................*/char xdata * pxchar xdata * data pxdata char xdata * px 这3 者有什么不同??char xdata * pxpx 本身存在于自动分配的空间,一般位于data 中,指向的内容位于xdatachar xdata * data pxpx 本身存在于data 空间,指向的内容位于xdatadata char xdata * px =char xdata *data pxdata:固定指前面0x00-0x7f 的128 个RAM,可以用acc直接读写的,速度最快,生成的代码也最小。
[计算机软件及应用]Keil C51软件使用说明
* ——表示是指针类型,此处*不含取内容之意;
数据类型——声明指针所指变量的类型;
[存储器类型1]——声明指针所指变量的存储类型,若默认则定义
为一般指针;
[存储器类型2]——声明该指针变量本身的存储类型;
标识符——声明指针变量本身的数据类型和名称.
22
MCS-51单片机原理、接口及应用
第6章 单片机的C51语言编程
6
MCS-51单片机原理、接口及应用
第6章 单片机的C51语言编程
6.1.2 C51中常用的头文件
reg51.h、reg52.h、math.h、ctype.h、stdio.h、stdlib.h、 absacc.h和intrins.h. 〔1〕reg51.h和reg52.h
〔定义51或52子系列单片机特殊功能寄存器和特殊位〕 reg52.h比reg51.h多了几行定义T2寄存器的内容.
第6章 单片机的C51语言编程
汇编语言:
优点:面向机器、目标代码短、占用存储器空间少、运行
快. 缺点:指令助记符多、编程灵活性差.
C语言: 优点:具有面向机器和面向用户的特点,良好的可读性﹑易
维护性和可移植性,对硬件的控制能力也很强, C语言的数据类 型及运算符丰富,具有良好的程序结构.
缺点:代码效率稍低〔同汇编语言相比〕,占用存储空间较 大. 解决方法:单片机内部都嵌入了大容量的Flash ROM,有效的 弥补了这个缺陷.
{
局部变量说明
执行语句〔包括子函数的调用语句〕
}
4
MCS-51单片机原理、接口及应用
第6章 单片机的C51语言编程
func1<形式参数及说明>
//子函数1
{ 局部变量说明
Keil C51使用详解
Keil C51使用详解keilc51使用详解v1.0电子设计世界!版权所有,热烈欢迎贴文,切勿修正并标明原文。
留存一切权利。
第一章keilc51开发系统基本知识 (6)1第一节系统概述 (6)第二节keilc51单片机软件开发系统的整体结构...6第三节keilc51工具包的加装...71.c51fordos72.c51forwindows的安装及注意事项:...7第四节keilc51工具包各部分功能及使用简介...71.c51与a51.72.l51和bl51.83.dscope51,tscope51及monitor51.84.ishell及uvision.9第二章keilc51软件使用详解 (10)第一节keilc51编译器的控制指令...101.源文件掌控类 (10)2.目标文件(object)控制类:...103.列表文件(listing)控制类:...10第二节dscope51的使用...111.dscope51fordos112.dscopeforwindows12第三节monitor51及其使用...131.monitor51对硬件的要求...132.mon51的使用...133.mon51的配置...134.串口连接图:...135.mon51命令及使用...14第四节集成开发环境(ide)的使用...141.ishellfordos的使用 (14)22.uvisionforwindows的使用 (15)第三章keilc51vs标准c..15第一节keilc51扩展关键字...15第二节内存区域(memoryareas):...161.pragramarea:...162.internaldatamemory:163.externaldatam emory.162.可位串行区表明20h-2fh..18第七节keilc51指针...181.通常指针...182.存储器指针...183.指针切换...18第八节keilc51函数...191.中断函数声明:...192.通用型存储工作区 (19)3.选通用存储工作区由usingx声明,见上例。
关于Keil C51指针的使用
关于KeilC51指针的使用(参见page106-113,keiluv2user'sguide09,2001)Keil中的指针分为两种:一种是普通指针,兼容标准C语言的指针;另一种我翻译成内存特殊指针(memory-specific pointers,翻译得不好:>)一.普通指针普通指针的定义方式如下:char * ptr;跟标准C的定义方式一样。
这种指针占三个字节,第一个字节是标识存储类型,是指针指向的变量的数据类型;第二个字节是指针存储地址的高位字节;第三个字节是指针存储地址的低位字节。
普通指针默认存储在内部存储器data,即片上RAM,如果想指定指针的存储位置,可以在*后加上存储类型,如下面几种定义方式:char * data ptr; //与char * ptr;等价,即默认的定义方式char * xdata ptr; //指针存储在片外RAMchar * idata ptr; //指针存储在idatachar * pdata ptr; //指针存储在pdata由定义普通指针写的程序最终代码比较长,运行速度相对较慢,因为Keil 在编译的时候不知道这个指针将要指向的变量的存储位置,只有当程序执行的时候才能知道,所以编译器不能对这段代码进行优化,不过,这样做的优点是此指针可以指向存储在任何位置的变量。
二.内存特殊指针内存特殊指针的定义方式为:char xdata * ptr;这个指针存储的时候占的字节数是不一定的,占一个字节的变量类型为:idata,data, pdata, bdata;占两个字节的变量类型为:code,xdata。
注意:char xdata * ptr;这里定义的ptr所指向的变量存储在xdata中,即外部变量,这样的话指针变量ptr占两个字节,我们再定义一个外部变量。
char xdata variable1;ptr=&variable1; //这样是正确的这段程序中,变量variable1存储在外部存储器中,是最合适的。
keil c51函数指针
Keil C51 中的函数指针和再入函数,函数指针与overlay=====调用树的保存C51不把函数参数压栈(除非使用再入函数)。
函数参数和全局变量被存入寄存器或固定的存储空间。
这样阻止函数的再入。
例如,一个函数调用它自己,它将覆盖它自己的参数或存储空间。
函数的再入问题通过关键字“reentrant”来解决。
函数指针的非再入函数的副作用,在执行中出现问题。
MAIN函数调用FUNC和FUNC_CALLER(根据调用树)。
用函数的指针来传递参数,调用树往往会出错。
=====转这篇文章是由Keil C51 的英文文档翻译过来的,很多语句都是根据自己的理解翻译的,肯定还有许多地方需要推敲。
希望读者能吸取到有用的部分,不要被误解了,自己多理解。
Overlay修改用于数据覆盖的调用树。
如果在用户程序里使用了函数指针,或者使用了像实时操作系统中调度器那样的跳转(k 指的是指针方式的调用吗?),那么,修改程序调用树将是很有必要的。
混合编程:函数名符号名解释viod func(void) FUNC 无参数传递,或不含寄存器参数的函数名不作改变转入目标文件中,名字只是简单地转为大写形式viod func(char) _FUNC 带寄存器参数的函数名加入“_”字符前缀,它表明这类函数包含寄存器内的参数传递viod func(viod) reentrant _?FUNC “_?”表示可重入,它表明该行数包含栈内的参数传递。
====将下面这篇的难点内容提到前面使用函数指针的附加说明如果你在C51中使用函数指针编程,有几个附加的说明你必须注意。
参数列表的限制通过函数指针传递参数给函数必须把所有的参数存入寄存器。
在大部分情况下,3个参数能够自动通过寄存器传递。
在C51的用户手册中能找到传递参数进入寄存器的运算法则。
但是并不保证,任何的3个数据类型可以传递。
因为C51在寄存器中传递3个参数,用于传递参数的存储空间是不被分配的,除非函数指向一个要求更多参数的函数。
C51语言的指针详解
单片机接口技术(C51版)第五章指针、结构、联合和枚举内容概述指针是C51语言的精华也是难点。
本章主要介绍指针的概念、定义指针的方法,介绍指向一维数组、二维数组、字符数组的指针使用方法,指针数组的概念以及指针作为函数参数的使用方法。
结构、联合和枚举是另外的构造型数据,本章介绍了这三种类型数据的定义、初始化以及使用方法。
教学目标1.理解指针的概念,掌握指针与地址的关系,能区别指针变量与变量的指针,根据需要定义并使用指针变量,理解地址运算的方法。
2.理解指针与数组的关系,熟练使用指针指向一维数组、二维数组,理解并掌握利用指针表达数组元素的几种表现形式。
3. 能利用指针指向字符数组,处理字符串。
4.理解指针数组的概念,该数组的元素是指针。
5.掌握指针作为函数形参的使用方法,理解指针作为函数形参传递整个数组的作用。
6.了解结构体的作用及应用场合,能定义并使用结构体变量,掌握结构变量成员的引用方法。
能定义并使用结构数组,会引用结构数组元素成员,7.掌握结构指针的定义方法,利用结构指针访问结构变量的成员。
8. 了解结构变量的作为结构成员的结构嵌套定义方法以及位结构的概念。
9. 理解联合的概念,能定义并使用联合体变量,掌握联合与结构的区别。
10. 能定义并使用枚举变量。
5.1指针5.1.1 指针和地址5.1.1.1 指针变量的定义⏹C51语言中, 对于变量的访问形式之一, 就是先求出变量的地址,然后再通过地址对它进行访问, 这就是这里所要论述的指针及其指针变量。
⏹所谓变量的指针, 实际上指变量的地址⏹变量的地址虽然在形式上好象类似于整数, 但在概念上不同于以前介绍过的整数, 它属于一种新的数据类型, 即指针类型。
⏹C51中, 一般用“指针”来指明这样一个表达式&x的类型,而用“地址”作为它的值, 也就是说, 若x为一整型变量, 则表达式&x的类型是指向整数的指针, 而它的值是变量x的地址。
⏹同样, 若double d;则&d的类型是指向双精度数d的指针, 而&d的值是双精度变量d的地址。
KeilC51中函数指针的使用
Keil C51中函数指针的使用3■江西理工大学 朱博 许伦辉 函数指针在C语言中应用较为灵活。
在单片机系统中,嵌入式操作系统、文件系统和网络协议栈等一些较为复杂的应用都大量地使用了函数指针。
K eil公司推出的C51编译器是事实上80C51C编程的工业标准,它针对8051系列CPU硬件在标准ANSI C的基础上进行了扩展;但由于编译器及8051体系结构的限制,造成了在使用函数指针时有很多与ANSI C不同的地方。
下面举例说明在不同的情形下函数指针的使用。
以下代码均在K eilμVision3、v8.08 C51、默认优化等级的开发环境下验证通过。
1 指向固定地址的指针在程序设计中,常需要跳转到某一特定的地址上执行,如引导程序的设计。
可通过如下C语言实现: int main(void){((void(code3)(void))0x2000)();return0;}此代码使得主函数执行位于0x2000地址的程序代码。
其中((void(code3)(void))是一种数据类型,表示一指向代码段函数的指针,该函数无参数和无返回值。
它对数据0x2000进行了强制类型转换,使函数指针指向地址为0x2000的代码段地址。
关于复杂类型的声明详见参考文献[1]。
通过反汇编窗口可看到编译器生成了如下汇编代码: C:0x000F 122000 LCALL C:2000由上可以看出,Keil C51是非常高效的编译器,产生了非常简洁的输出。
这正是我们所期望的。
2 无参数的函数指针Keil C51中不带参数的函数指针的使用方法与ANSI3国家自然科学基金项目(No:60664001):基于分布式多智能体的城市交通协调控制理论及应用研究。
C基本相同。
示例如下: void foo(void){ return;}int main(void){ void(3pfoo)(void);//声明函数指针pfoo pfoo=foo;//对该指针赋值,使该指针指向某一函数 (3pfoo)();//通过指针调用其指向的函数 return0;}3 带参数的函数指针一般来说,函数参数是通过堆栈来传递,用PUSH和POP汇编指令来实现的;但由于8051体系及其编译器的一些限制,使得其函数参数的传递需要一些特殊的方法。
keil c51指针参数调用
keil c51指针参数调用在嵌入式系统开发中,Keil C51是一种常用的编译器,特别适用于C语言的嵌入式开发。
在Keil C51中,指针参数的调用是一种常见的编程技巧,本文将介绍指针参数的概念、用法以及一些注意事项。
一、指针参数的概念指针是C语言中一种非常重要的数据类型,它存储了一个变量的内存地址。
通过指针,我们可以间接地访问和修改对应的变量。
指针参数是指在函数的参数列表中使用指针作为形参的一种方式。
二、指针参数的用法在Keil C51中,使用指针参数可以实现函数间的数据共享和传递。
具体而言,指针参数可以用于以下几个方面:1. 传递数组数组在C语言中是一种连续存储的数据结构,通过指针参数可以高效地传递数组给函数。
在函数中,可以通过指针来访问和修改数组元素的值。
2. 传递结构体结构体是C语言中一种用户自定义的数据类型,由多个不同类型的成员变量组成。
通过指针参数,可以将结构体传递给函数,并在函数中对结构体的成员进行操作。
3. 函数返回多个值在某些情况下,一个函数可能需要返回多个值。
通过指针参数,可以将多个变量的地址传递给函数,并在函数中将结果保存到这些地址对应的变量中。
三、指针参数的注意事项使用指针参数需要注意以下几个问题:1. 空指针检查在使用指针参数之前,需要先检查指针是否为空。
如果指针为空,可能导致程序崩溃或者产生不可预料的结果。
2. 指针的生命周期在使用指针参数时,需要注意指针的生命周期。
确保指针指向的内存空间在使用期间一直有效,避免访问已经释放的内存。
3. 指针的类型匹配指针参数的类型必须与实际参数的类型匹配,否则会导致编译错误。
在使用指针参数时,需要注意类型的一致性。
四、示例代码下面是一个简单的示例代码,演示了如何在Keil C51中使用指针参数:```c#include <stdio.h>// 传递数组给函数void printArray(int *arr, int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]);}printf("\n");}// 传递结构体给函数struct Point {int x;int y;};void printPoint(struct Point *p) {printf("(%d, %d)\n", p->x, p->y); }// 函数返回多个值void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;}int main() {int arr[] = {1, 2, 3, 4, 5};int size = sizeof(arr) / sizeof(int);printArray(arr, size);struct Point p = {10, 20};printPoint(&p);int a = 10, b = 20;swap(&a, &b);printf("a = %d, b = %d\n", a, b);return 0;}```在上述示例代码中,我们定义了三个函数:`printArray`用于打印数组,`printPoint`用于打印结构体,`swap`用于交换两个变量的值。
c51中指针的用法
MOVX @DPTR, A
第5种情况:
uchar * data pstr;
pstr=tmp;
大家注意到"*"前的关键字声明没有了,是的这样会发生什么事呢?下面这么写呢!对了用齐豫的一首老歌名来说就是 “请跟我
uchar xdata * xdata pstr;
pstr=tmp;
这中情况也是对的,但效率不如第2种情况。编译后的汇编代码如下。
MOV DPTR, #0x000A ;0x000A,0x000B是在外ram区分配的pstr指针变量地址空间
MOV A, #tmp(0x00)
MOV DPTR, #0x000A ;0x000A-0x000C是在外ram区分配的pstr指针变量地址空间
MOV A, #0x01
MOV @DPTR, A
INC DPTR
MOV DPTR, #0x000A
MOV A, #tmp(0x00)
px=(int xdata *)0x4000;
//表示从 xdata 0x4000处取一个 char 给x
x=*((char xdata *)0x4000); (可以将0X4000处,改成一个整形变量,方便进行操作。)
或者*((char xdata *)0x4000)=X;//表示给存在xdata中,地址为0x4000的空间赋值。
与指针有关的各种说明和意义见下表。
int *p; p为指向整型量的指针变量;
int xdata *p; 存在外部数据RAM;
int data *p; 存在内部数据RAM;
xdata ---> 可寻址片外ram (64k 地址范围)
Keil C51使用详解
Keil C51使用详解第一章Keil C51开发系统基本知识 (6)第一节系统概述 (6)第二节Keil C51单片机软件开发系统的整体结构 (6)第三节Keil C51工具包的安装 (7)1. C51 for Dos 72. C51 for Windows的安装及注意事项: (7)第四节Keil C51工具包各部分功能及使用简介 (7)1. C51与A51. 72. L51和BL51. 83. DScope51,Tscope51及Monitor51. 84. Ishell及uVision. 9第二章Keil C51软件使用详解 (10)第一节Keil C51编译器的控制指令 (10)1. 源文件控制类 (10)2. 目标文件(Object)控制类: (10)3. 列表文件(listing)控制类: (10)第二节dScope51的使用 (11)1. dScope51 for Dos 112. dScope for Windows 12第三节Monitor51及其使用 (13)1. Monitor51对硬件的要求 (13)2. Mon51的使用 (13)3. MON51的配置 (13)4. 串口连接图: (13)5. MON51命令及使用 (14)第四节集成开发环境(IDE)的使用 (14)1. Ishell for Dos的使用 (14)2. uVision for windows的使用 (15)第三章Keil C51 vs 标准C.. 15第一节Keil C51扩展关键字 (15)第二节内存区域(Memory Areas): (16)1. Pragram Area: (16)2. Internal Data Memory: 163. External Data Memory. 164. Speciac Function Register Memory. 16第三节存储模式 (16)1. Small模式 (16)2. Compact模式 (17)3. large模式 (17)第四节存储类型声明 (17)第五节变量或数据类型 (17)第六节位变量与声明 (17)1. bit型变量 (17)2. 可位寻址区说明20H-2FH.. 18第七节Keil C51指针 (18)1. 一般指针 (18)2. 存储器指针 (18)3. 指针转换 (18)第八节Keil C51函数 (19)1. 中断函数声明: (19)2. 通用存储工作区 (19)3. 选通用存储工作区由using x声明,见上例。
51c语言指针的用法
51c语言指针的用法指针是C语言中非常重要的概念,它提供了一种间接访问内存地址的方式,使得程序能够更加灵活地操作内存。
在51C语言中,指针的用法与C语言基本相同,本文将介绍一些常见的指针用法。
首先,我们需要了解指针的定义和声明。
在51C语言中,指针的定义和声明与C语言相同,使用"*"符号来表示指针类型。
例如,int *p;表示定义了一个指向整型变量的指针p。
指针变量必须在使用之前进行初始化,可以通过赋值操作将指针指向某个变量的地址。
指针的一个重要用途是动态内存分配。
在51C语言中,可以使用malloc函数来动态分配内存。
malloc函数接受一个参数,表示需要分配的内存大小,并返回一个指向分配内存的指针。
例如,int *p = (int*)malloc(sizeof(int)); 表示分配了一个整型变量大小的内存,并将其地址赋给指针p。
分配完内存后,可以通过指针来访问和操作这块内存。
指针还可以用于函数的参数传递。
在C语言中,函数的参数传递是通过值传递的方式,即传递的是变量的副本。
但是,通过传递指针作为参数,可以实现对变量的引用传递,从而在函数内部修改变量的值。
例如,void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } 表示定义了一个交换两个整型变量值的函数swap,通过传递指针作为参数,可以在函数内部交换变量的值。
指针还可以用于数组的访问。
在C语言中,数组名本身就是一个指针,指向数组的第一个元素的地址。
通过指针可以访问数组的各个元素。
例如,int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; 表示定义了一个整型数组arr,并将数组的第一个元素的地址赋给指针p。
通过指针p可以访问数组的各个元素,例如,*p表示数组的第一个元素,*(p+1)表示数组的第二个元素。
指针还可以用于动态数据结构,例如链表和树等。
keil C51 指针总结
keil C51 指针总结上课所提到变量就是一种在程序执行过程中其值能不断变化的量。
要在程序中使用变量必须先用标识符作为变量名,并指出所用的数据类型和存储模式,这样编译系统才能为变量分配相应的存储空间。
定义一个变量的格式如下:[存储种类] 数据类型[存储器类型] 变量名表在定义格式中除了数据类型和变量名表是必要的,其它都是可选项。
存储种类有四种:自动(auto),外部(extern),静态(static)和寄存器(register),缺省类型为自动(auto)。
这些存储种类的具体含义和使用方法,将在第七课《变量的存储》中进一步进行学习。
而这里的数据类型则是和我们在第四课中学习到的名种数据类型的定义是一样的。
说明了一个变量的数据类型后,还可选择说明该变量的存储器类型。
存储器类型的说明就是指定该变量在单片机c语言硬件系统中所使用的存储区域,并在编译时准确的定位。
表6-1中是KEIL uVision2所能认别的存储器类型。
注意的是在AT89c51芯片中RAM只有低128位,位于80H到FFH的高128位则在52芯片中才有用,并和特殊寄存器地址重叠。
特殊寄存器(SFR)的地址表请看附录二AT89c51特殊功能寄存器列表如果省略存储器类型,系统则会按编译模式SMALL,COMPACT或LARGE所规定的默认存储器类型去指定变量的存储区域。
无论什么存储模式都能声明变量在任何的8051存储区范围,然而把最常用的命令如循环计数器和队列索引放在内部数据区能显著的提高系统性能。
还有要指出的就是变量的存储种类与存储器类型是完全无关的。
. 数据存储模式存储模式决定了没有明确指定存储类型的变量,函数参数等的缺省存储区域,共三种:1. 1. Small模式所有缺省变量参数均装入内部RAM,优点是访问速度快,缺点是空间有限,只适用于小程序。
2. 2. Compact模式所有缺省变量均位于外部RAM区的一页(256Bytes),具体哪一页可由P2口指定,在STARTUP.A51文件中说明,也可用pdata指定,优点是空间较Small为宽裕速度较Small慢,较large要快,是一种中间状态。
第7章C51的指针
北京源智天下科技有限公司
1-21
联系方式:
指向一维数组的指针
• 指向一维数组的指针是将指针变量指向一维数组的 首地址或者某个元素的地址。 • 数组元素在内存中是连续存放的,通过指针变量 pp及其有关运算可以间接访问数组中的任何一个 元素。例如:
– a+i和pp+i均表示数组元素a[i]的地址; – *(pp+i)和*(a+i)都表示pp+i和a+i所指向元素的值;
char *p="Hello everyone!";
北京源智天下科技有限公司
1-11
联系方式:
特殊的指针变量赋值——函数入口
• 指针变量还可以指向函数。 • 对指向函数的指针变量赋值,就是把函数 的入口首地址赋予指向函数的指针变量。
北京源智天下科技有限公司
取值运算符*
• 取值运算符*就是提取指针变量所指向内存单元中 的数据内容。 • 取值运算符*也是单目运算符,同样符合自右至左 的结合性。 • 取值运算符*的使用格式如下: – *指针变量名
北京源智天下科技有限公司
1-16
联系方式:
取值运算符*
• 取内容运算符*和指针变量声明中指针说明符*是不 同的,读者应该分清两者的区别。
1-25
联系方式:
指针和数组的关系总结
• • • • 指针和数组有着十分紧密的关系。 数组和指针的使用方法十分灵活,也很容易混淆,读者应 该多加练习。 一般来说,任何能由数组和数组下标完成的操作,也都完 全可以用指针和指针的偏移量来实现。 详细内容参阅书中介绍。
1-12
联系方式:
用函数为指针变量赋值注意事项
• 注意其表示方法两对括号都不能省略。 • 对指针变量pf赋值时,函数名fun前没有地址运算 符“&” 。 • 在C51语言中,指针变量若不带初始化项,其将被 初始化为NULL。 • 空指针常用于调用一个带有返回指针的函数时。
C51的指针函数
C51的指针函数用得并不多,但是指针函数应用的恰到好处可以给写出比较简洁的程序。
这篇文章比较好的介绍了C51 的指针函数。
#define ubyte unsigned char#define uint unsigned int#define ulong unsigned longubyte kbCode; // 按键编码纪录ubyte kbStatus; // 键盘当前状态,可以理解为菜单层次// 按键的四种不同工作状态对应的函数指针对照表,每三字节对应一个按键// 每一项包含三个字节,分别代表按键码,键盘状态,对应处理程序编号// 本表对应于日常操作,不是修改状态ubyte code TAB0[46]={0x11,0x00,0x01, // 按键'1' func10x12,0x00,0x01, // 按键'2' func10x14,0x00,0x01, // 按键'3' func10x1a,0x00,0x01, // 按键'4' func10x2a,0x00,0x01, // 按键'5' func10x4a,0x00,0x01, // 按键'6' func10x01,0x00,0x01, // 按键'7' func10x02,0x00,0x01, // 按键'8' func10x04,0x00,0x01, // 按键'9' func10x10,0x00,0x01, // 按键'0' func10x20,0x00,0x01, // 按键'.' func10x08,0x00,0x02, // 按键'Clear' func20x18,0x00,0x03, // 按键'U/D' func30x8a,0x01,0x04, // 按键'shift' func40x40,0x02,0x05, // 按键'last' func50x00}; // 本表结束标志ubyte code TAB1[40]={0x12,0x03,0x06, // 按键'2' func60x14,0x03,0x07, // 按键'3' func70x2a,0x03,0x08, // 按键'5' func80x4a,0x03,0x09, // 按键'6' func90x01,0x03,0x12, // 按键'7' func180x8a,0x03,0x14, // 按键'shift' func200x11,0x01,0x0a, // 按键'1' func100x1a,0x01,0x0b, // 按键'4' func110x04,0x01,0x0c, // 按键'9' func120x10,0x01,0x0d, // 按键'0' func130x80,0x01,0x0e, // 按键'Enter' func140x08,0x00,0x02, // 按键'Clear' func20x20,0x03,0x13, // 按键'.' func190x00}; // 本表结束标志ubyte code TAB2[7]={0x40,0x02,0x0f, // 按键'last' func150x08,0x00,0x02, // 按键'Clear' func20x00}; // 本表结束标志ubyte code TAB3[40]={0x11,0x03,0x10, // 按键'1' func160x12,0x03,0x10, // 按键'2' func160x14,0x03,0x10, // 按键'3' func160x1a,0x03,0x10, // 按键'4' func160x2a,0x03,0x10, // 按键'5' func160x4a,0x03,0x10, // 按键'6' func160x01,0x03,0x10, // 按键'7' func160x02,0x03,0x10, // 按键'8' func160x04,0x03,0x10, // 按键'9' func160x10,0x03,0x10, // 按键'0' func160x20,0x03,0x10, // 按键'.' func160x08,0x00,0x02, // 按键'clear' func20x80,0x01,0x11, // 按键'Enter' func170x00}; // 本表结束标志ubyte code *TAB[4]={TAB0,TAB1,TAB2,TAB3}; // 总指针表// 指针函数列表code void(code *KeyProcTab[])()={NoKey, /*0# (00H)#*/func1, /*1# (01H)#*/func2, /*2# (02H)#*/func3, /*3# (03H)#*/func4, /*4# (04H)#*/func5, /*5# (05H)#*/func6, /*6# (06H)#*/func7, /*7# (07H)#*/func8, /*8# (08H)#*/func9, /*9# (09H)#*/func10, /*10# (0AH)#*/func11, /*11# (0BH)#*/func12, /*12# (0CH)#*/func13, /*13# (0DH)#*/func14, /*14# (0EH)#*/func15, /*15# (0FH)#*/func16, /*16# (10H)#*/func17, /*17# (11H)#*/func18, /*18# (12H)#*/func19, /*19# (13H)#*/func20 /*20# (14H)#*/};void NoKey(){return;}void func0(){;}void func1(){;}....................void func20(){;}///////////////////////////////////////////////////////////////////// /// 键盘监控,根据当前状态特征指向不同的指针表,并调用相应的函数 // ///////////////////////////////////////////////////////////////////// /void mon(ubyte key){ubyte code *data pTab;kbCode=key;pTab=*(TAB+kbStatus); // 根据当前状态特征指向分指针表while(*pTab != key && *pTab != 0) // 按照按键代码查表{pTab += 3; // 查表}if(*pTab!=0){pTab++;kbStatus=*pTab; // 取状态特征字节pTab++; // 指向执行函数(*KeyProcTab[*pTab])(); // 指针函数调用}}。
KeilC51中函数指针使用注意事项
KeilC51中函数指针使用注意事项在我们的代码中大量使用了函数指针。
当函数指针用在KeilC51中时,一定要注意编译器自动生成的函数调用树通常是不正确的,需要手动调整。
否则可能造成无法预知的后果。
这是因为,KeilC51编译器并不把函数参数和局部变量压入堆栈中,而是放在寄存器或固定的内存位置。
C51的编译器监视函数调用的嵌套顺序,把几个函数的变量放在同样固定的位置。
在C51编译器中连接器会搜索所有函数中变量占用存储区间最多的函数,然后以这个函数的变量的占用空间开辟一片空间,其他函数的变量也放在该空间中,同时实现了变量的覆盖(无相互调用)与地址的共享。
例如函数A占10个字节,函数B占20个字节,函数C占15个字节,如果它们之间没有相互调用则仅需20个字节就可以满足45个字节的变量需要。
正是由于所有函数的参数和局部变量的共享一个覆盖区,函数没有相互的调用时,在执行一个函数时,会将另一个函数的变量的存储区覆盖。
如果函数有调用,那么不会覆盖原来函数的局部变量的区间。
调用树(calltree)是由Keil链接器自动生成的,用于描述函数的调用关系(调用树可通过编译生成的某.M51文件的OVERLAYMAPOFMODULE部分查看,该部分详细的说明了函数的调用关系以及对覆盖存储区的使用情况)。
链接器通过分析调用树来确定哪些寄存器或内存位置是可安全覆盖的。
这样两个不同时调用的函数就可以共享同一块内存用于传递参数和存储局部变量。
但对于函数指针来说,编译器并不知道函数指针将指向哪个函数。
这导致了调用树构造出错的可能,函数的参数和局部变量也可能被错误覆盖(例如,函数A通过函数指针调用了函数B,但编译器并不知道它们之间存在调用关系,所以认为它们是可以共享同一块内存的。
这样当函数A调用了函数B,回到函数A后,函数A的参数和局部变量可能已经被改变了,再往下运行就出错了)。
对此,Keil提供了链接器OVERLAY伪指令,可让用户自行修改调用树,调整函数的调用关系。
Keil C51中函数指针的使用
Keil C51中函数指针的使用
朱博;许伦辉
【期刊名称】《单片机与嵌入式系统应用》
【年(卷),期】2008(000)005
【摘要】@@ 函数指针在C语言中应用较为灵活.在单片机系统中,嵌入式操作系统、文件系统和网络协议栈等一些较为复杂的应用都大量地使用了函数指针.Keil 公司推出的C51编译器是事实上80C51 C编程的工业标准,它针对8051系列CPU硬件在标准ANSI C的基础上进行了扩展;但由于编译器及8051体系结构的限制,造成了在使用函数指针时有很多与ANSI C不同的地方.下面举例说明在不同的情形下函数指针的使用.以下代码均在Keil μVision3、v8.08 C51、默认优化等级的开发环境下验证通过.
【总页数】2页(P71-72)
【作者】朱博;许伦辉
【作者单位】江西理工大学;江西理工大学
【正文语种】中文
【中图分类】TP3
【相关文献】
1.Keil C51软件使用方法 [J], 张亚峰
2.Keil C51中C51程序与汇编程序的接口方法 [J], 张玉峰;荀建军
3.Keil C51中变量的使用 [J], 阮海蓉
4.Proteus和Keil C51在单片机实验教学中的应用研究 [J], 郭一军;周武;胡娟
5.基于80C51和KEIL C51的LED点阵显示系统 [J], 简献忠;虞箐;熊晓君;赵虎;居滋培
因版权原因,仅展示原文概要,查看原文内容请购买。
(教程)Keil c51指针变量
Keil c51指针变量单片机c语言支持一般指针(Generic Pointer)和存储器指针(Memory_Specific Pointer)。
1. 1. 一般指针一般指针的声明和使用均与标准C相同,不过同时还能说明指针的存储类型,例如:long * state;为一个指向long型整数的指针,而state本身则依存储模式存放。
char * xdata ptr;ptr为一个指向char数据的指针,而ptr本身放于外部RAM区,以上的long,char等指针指向的数据可存放于任何存储器中。
一般指针本身用3个字节存放,分别为存储器类型,高位偏移,低位偏移量。
2. 2. 存储器指针基于存储器的指针说明时即指定了存贮类型,例如:char data * str;str指向data区中char型数据int xdata * pow; pow指向外部RAM的int型整数。
这种指针存放时,只需一个字节或2个字节就够了,因为只需存放偏移量。
3. 3. 指针转换即指针在上两种类型之间转化:l 当基于存储器的指针作为一个实参传递给需要一般指针的函数时,指针自动转化。
l 如果不说明外部函数原形,基于存储器的指针自动转化为一般指针,导致错误,因而请用“#include”说明所有函数原形。
l 能强行改变指针类型。
变量的存储类别一、static(静态局部)变量。
1、静态局部变量在程序整个运行期间都不会释放内存。
2、对于静态局部变量,是在编译的时候赋初值的,即只赋值一次。
如果在程序运行时已经有初值,则以后每次调用的时候不再重新赋值。
3、如果定义局部变量的时候不赋值,则编译的时候自动赋值为0。
而对于自动变量而言,定义的时候不赋值,则是一个不确定的值。
4、虽然静态变量在函数调用结束后仍然存在,但是其他函数不能引用。
二、用extern声明外部变量。
用extern声明外部变量,是为了扩展外部变量的作用范围。
比如一个程序能由多个源程序文件组成。
KEIL C51使用技巧
函数的递归调用和再入函数函数类型函数名(形参表)[reentrant]再入函数可被递归调用,无论何时,包括中断服务函数在内的任何函数都可调用再入函数。
与非再入函数的参数传递和局部变量的存储分配方式不同,Cx51编译器为再入函数生成一个模拟栈,通过其来完成参数传递和存放局部变量。
模拟栈所在的存储器空间根据再入函数存储器模式的不同,可以是DA TA、PDATA、XDATA 存储器空间。
当程序中包含有多种存储器模式的再入函数时,编译器为每种模式单独建立一个模拟栈并独立管理各自的栈指针。
对于再入函数有如下规定:(1)再入函数不能传送bit类型的参数,也不能定义一个局部位变量,再入函数不能包括位操作和8051系列单片机的可位寻址区(2)与PL/M51兼容的函数不能具有reentrant属性,也不能调用再入函数(3)编译时存储器模式基础上为再入函数在内部或外部存储器中建立一个模拟堆栈区,称为再入栈。
在small模拟下再入栈位于idata区,在compact模式下再入栈位于pdaa 区,在large模式下再入栈位于xdata区。
再入函数的局部变量及参数都被放入再入栈中,从而使再入函数可进行递归调用。
而非再入函数的局部变量被放在再入栈外的暂存区内,如对其进行递归调用,则上次调用时使用的局部变量数据将被覆盖。
(4)在同意个程序中可定义或使用不同存储器模式的再入函数,任意模式的再入函数不能调用不同模式的再入函数,但可任意调用非再入函数。
(5)在参数的传递上,实际参数可传递给间接调用的再入函数。
无再入属性的间接调用函数不能包含调用参数,但可以使用定义的全局变量来进行参数传递。
采用函数递归调用可使程序结构紧凑,但要求采用再入函数,以便利用再入栈来保存有关的局部变量数据,因此要占用较大的内存空间。
另外,递归调用时对函数的处理速度较慢,因此一般情况下应尽量避免使用函数递归调用,定义函数时应尽量避免使用再入属性。
8051常规栈是位于内部数据RAM中,是向上生长型的而模拟再入栈是向下生长型的。
单片机C语言教程:C51指针的使用
单片机C语言教程:C51指针的使用指针就是指变量或数据所在的存储区地址。
如一个字符型的变量STR 存放在内存单元DATA 区的51H 这个地址中,那么DATA 区的51H 地址就是变量STR 的指针。
在 C 语言中指针是一个很重要的概念,正确有效的使用指针类型的数据,能更有效的表达复杂的数据结构,能更有效的使用数组或变量,能方便直接的处理内存或其它存储区。
指针之所以能这么有效的操作数据,是因为无论程序的指令、常量、变量或特殊寄存器都要存放在内存单元或相应的存储区中,这些存储区是按字节来划分的,每一个存储单元都能用唯一的编号去读或写数据,这个编号就是常说的存储单元的地址,而读写这个编号的动作就叫做寻址,通过寻址就能访问到存储区中的任一个能访问的单元,而这个功能是变量或数组等是不可能代替的。
C 语言也因此引入了指针类型的数据类型,专门用来确定其他类型数据的地址。
用一个变量来存放另一个变量的地址,那么用来存放变量地址的变量称为指针变量。
如用变量STRIP 来存放文章开头的STR 变量的地址51H,变量STRIP 就是指针变量。
下面用一个图表来说明变量的指针和指针变量两个不一样的概念。
变量的指针就是变量的地址,用取地址运算符取得赋给指针变量。
STR 就是把变量STR 的地址取得。
用语句STRIP = STR 就能把所取得的STR 指针存放在STRIP 指针变量中。
STRIP 的值就变为51H。
可见指针变量的内容是另一个变量的地址,地址所属的变量称为指针变量所指向的变量。
要访问变量STR 除了能用STR 这个变量名来访问之外,还能用变量地址来访问。
方法是先用STR 取变量地址并赋于STRIP 指针变量,然后就能用*STRIP 来对STR 进行访问了。
*是指针运算符,用它能取得指针变量所指向。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Keil C51中函数指针使用注意事项
在我们的代码中大量使用了函数指针。
当函数指针用在Keil C51中时,一定要注意编译器自动生成的函数调用树通常是不正确的,需要手动调整。
否则可能造成无法预知的后果。
这是因为,Keil C51编译器并不把函数参数和局部变量压入堆栈中,而是放在寄存器或固定的内存位置。
C51的编译器监视函数调用的嵌套顺序,把几个函数的变量放在同样固定的位置。
在C51编译器中连接器会搜索所有函数中变量占用存储区间最多的函数,然后以这个函数的变量的占用空间开辟一片空间,其他函数的变量也放在该空间中,同时实现了变量的覆盖(无相互调用)与地址的共享。
例如函数A占10个字节,函数B占20个字节,函数C占15个字节,如果它们之间没有相互调用则仅需20个字节就可以满足45个字节的变量需要。
正是由于所有函数的参数和局部变量的共享一个覆盖区,函数没有相互的调用时,在执行一个函数时,会将另一个函数的变量的存储区覆盖。
如果函数有调用,那么不会覆盖原来函数的局部变量的区间。
调用树(call tree)是由Keil链接器自动生成的,用于描述函数的调用关系(调用树可通过编译生成的*.M51文件的OVERLAY MAP OF MODULE部分查看,该部分详细的说明了函数的调用关系以及对覆盖存储区的使用情况)。
链接器通过分析调用树来确定哪些寄存器或内存位置是可安全覆盖的。
这样两个不同时调用的函数就可以共享同一块内存用于传递参数和存储局部变量。
但对于函数指针来说,编译器并不知道函数指针将指向哪个函数。
这导致了调用树构造出错的可能,函数的参数和局部变量也可能被错误覆盖(例如,函数A通过函数指针调用了函数B,但编译器并不知道它们之间存在调用关系,所以认为它们是可以共享同一块内存的。
这样当函数A调用了函数B,回到函数A后,函数A的参数和局部变量可能已经被改变了,再往下运行就出错了)。
对此,Keil提供了链接器OVERLAY伪指令,可让用户自行修改调用树,调整函数的调用关系。
删除调用关系,命令格式:
OVERLAY (sfname-caller ~ sfname-callee)
OVERLAY (sfname-caller ~ (sfname-callee, sfname-callee))
举例:OVERLAY(?PR?_FUNC?DMAIN ~ (?PR?_FUNC_A?DMAIN,?PR?_FUNC_B?DMAIN)) 意思是从FUNC函数中删除对FUNC_A和FUNC_B的调用。
添加调用关系,命令格式:
OVERLAY (sfname-caller ! sfname-callee)
OVERLAY (sfname-caller ! (sfname-callee, sfname-callee))
举例:OVERLAY(?PR?_MAIN?DMAIN ! (?PR?_FUNC_A?DMAIN,?PR?_FUNC_B?DMAIN)) 意思是添加FUNC函数对FUNC_A和FUNC_B的调用。
可在链接命令行输入命令。
或在Keil集成开发环境中,在“BL51 Misc”-“Overlay”中填入()中的内容。