一、認識函數指針
如果在程序中定義了一個函數,那麼在編譯時系統就會爲這個函數代碼分配一段存儲空間,這段存儲空間的首地址稱爲這個函數的地址。而且函數名錶示的就是這個地址
函數指針的定義方式爲:
函數返回值類型 (* 指針變量名) (函數參數列表);
函數指針的定義就是將“函數聲明”中的“函數名”改成“(*指針變量名)”
兩端的括號不能省略,括號改變運算符的優先級,省略括號*將與前面的返回值類型結合表示返回值爲指針類型
判斷一個指針變量是指向變量的指針變量還是指向函數的指針變量呢?首先看變量名前面有沒有“”,如果有“”說明是指針變量;其次看變量名的後面有沒有帶有形參類型的圓括號,如果有就是指向函數的指針變量,即函數指針,如果沒有就是指向變量的指針變量。
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數組存儲的應當也是地址值)