一、认识函数指针
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址
函数指针的定义方式为:
函数返回值类型 (* 指针变量名) (函数参数列表);
函数指针的定义就是将“函数声明”中的“函数名”改成“(*指针变量名)”
两端的括号不能省略,括号改变运算符的优先级,省略括号*将与前面的返回值类型结合表示返回值为指针类型
判断一个指针变量是指向变量的指针变量还是指向函数的指针变量呢?首先看变量名前面有没有“”,如果有“”说明是指针变量;其次看变量名的后面有没有带有形参类型的圆括号,如果有就是指向函数的指针变量,即函数指针,如果没有就是指向变量的指针变量。
int Func(int x); /*声明一个函数*/
int (*p) (int x); /*定义一个函数指针*/
p = Func; /*将Func函数的首地址赋给指针变量p*/
赋值时函数 Func 不带括号,也不带参数。由于函数名 Func 代表函数的首地址,因此经过赋值以后,指针变量 p 就指向函数 Func() 代码的首地址了
使用:
int Max(int, int); //函数声明
int(*p)(int, int); //定义一个函数指针
int a, b, c;
p = Max; //把函数Max赋给指针变量p, 使p指向Max函数
printf("please enter a and b:");
scanf("%d%d", &a, &b);
c = (*p)(a, b); //通过函数指针调用Max函数
重点关注:c = (*p)(a, b); //通过函数指针调用Max函数
延伸:
1.定义函数指针类型:
typedef int (*fun_ptr)(int,int);
2.声明变量,赋值:
fun_ptr max_func=max;
也就是说,赋给函数指针的函数应该和函数指针所指的函数原型是一致的。
3.使用
max_func(a,b);
指针函数:返回值为指针的函数
函数指针数组
为函数指针数组赋值有两种方式:静态定义和动态赋值。
- 静态定义
在定义函数指针数组的时候,已经确定了每个成员所对应的函数。例如:
void(*Array[])(void)={Stop,Run,Jump};
从根本上讲函数指针数组依然是数组,所以和数组的定义类似,由于是静态赋值,[ ]里面的数字可以
省略。这个函数指针数组的成员有三个。
Array[1]();//执行Run函数
- 动态赋值
也可以先定义一个函数指针数组,在需要的时候为其赋值。为了还原其本来面目,我们先对这个执行特定类型的函数指针进行类型重定义,然后再用这个新数据类型来定义数组。如下:
typedef void(*Funcint)(void);//此类型的函数指针指向的是无参、无返回值的函数。
Funcint Array[32];//定义一个函数指针数组,其每个成员为Funcint类型的函数指针
Array[10]=INT_TIMER0;//为其赋值
Array[10]();//调用函数指针数组的第11个成员指向的函数
二、解读TivaWare头文件
文件路径:ti\TivaWare_C_Series-2.1.4.178\driverlib\rom.h
//*****************************************************************************
//
// Pointers to the main API tables.
//
//*****************************************************************************
#define ROM_APITABLE ((uint32_t *)0x01000010)
#define ROM_VERSION (ROM_APITABLE[0])
#define ROM_UARTTABLE ((uint32_t *)(ROM_APITABLE[1]))
#define ROM_SSITABLE ((uint32_t *)(ROM_APITABLE[2]))
#define ROM_I2CTABLE ((uint32_t *)(ROM_APITABLE[3]))
#define ROM_GPIOTABLE ((uint32_t *)(ROM_APITABLE[4]))
#define ROM_ADCTABLE ((uint32_t *)(ROM_APITABLE[5]))
……
本指针表为指针的宏定义。
((uint32_t *)(ROM_APITABLE[1]))
将指针地址(ROM_APITABLE[1]) 强制类型转换为(uint32_t *)指针
指针表图示如下:
ROM中API表从地址0x0100010开始,每4个字节存一个uint32_t型数据,指向一个子表的首地址
以rom.h 头文件中关于GPIO函数的定义为例:
#if defined(TARGET_IS_TM4C123_RA1) ||
defined(TARGET_IS_TM4C123_RA3) ||
defined(TARGET_IS_TM4C123_RB1) ||
defined(TARGET_IS_TM4C123_RB2) ||
defined(TARGET_IS_TM4C129_RA0) ||
defined(TARGET_IS_TM4C129_RA1) ||
defined(TARGET_IS_TM4C129_RA2)
#define ROM_GPIOIntTypeGet
((uint32_t (*)(uint32_t ui32Port,
uint8_t ui8Pin))ROM_GPIOTABLE[4])
#endif
- 定义芯片型号TARGET_IS_TM4C123_RB1的作用,这里是一个条件编译
- 宏定义 ROM_GPIOIntTypeGet 是一个强制类型转换:
(
(uint32_t ( * ) (uint32_t ui32Port, uint8_t ui8Pin))
ROM_GPIOTABLE[4]
)
把 ROM_GPIOTABLE[4] 转换为一个函数指针 uint32_t ( * ) (uint32_t ui32Port, uint8_t ui8Pin) ,指向地址ROM_GPIOTABLE[4]处
看到这里是一个基址寻址,ROM_APITABLE是一个uint32_t型指针,指向地址 0x01000010,这样可以把它看做一个uint32_t数组
ROM_GPIOTABLE是(uint32_t )(ROM_APITABLE[4]),即取ROM_APITABLE数组的第4个元素(地址为0x01000010+44)的值,然后用一个unt32_t型指针指向这个值。(ROM_APITABLE数组存储的应当也是地址值)