例程:
int i; //定義乙個測試變數
void test() //定義乙個函式
int main()
//經常見到嵌入式設計中,將某一程式段的入口位址轉換為乙個函式,我們來分析一下它的成分:
如在bootloader的0x00000020位址上的雙字單元中有這樣一條語句:
@address is 0x00000020
bpowerdown @jump to the flag "powerdown"
......
powerdown:
......
然後在某一c標頭檔案中可以見到這樣的巨集宣告:
#define enterpwdn(clkcon) ((void (*)(int))0x20)(clkcon)
初一看,亂七八糟的,現在,我們來整理一下。
不難看出,當我們程式設計呼叫enterpwdn(clkcon)函式的時候,編譯器在編譯前首先把enterpwdn(clkcon)轉換為
((void (*)(int))0x20)(clkcon)語句。
對於這個語句,我們將之分解成3部分來看。
1:(void (*)(int)
2:0x20
3:(clkcon)
(clkcon)是函式的引數,就不用說了。0x20呢?當然就是要轉換的函式的入口位址了。那對於(void(*)(int)呢??呵呵……,這一部分作為乙個整體,描述了轉換後的函式的型別,即無返回值,帶乙個整形引數。而中間那個」(*)「,就表示要轉換成乙個函式(或者說把0x20轉換為乙個位址,因為在arm彙編中,就把c語言的函式名當作乙個位址標號看待了)。就像我們平常用的強制型別轉換一樣,(int)temp,只不過這裡是將乙個數轉換為另一型別,而那是將乙個位址轉換為乙個函式罷了。
關於arm中:#define enterpwdn(clkcon)((void (*)(int))0x00000020)(clkcon)
1。首先要知道帶引數的巨集定義。定義方法如下:
#define 巨集名(引數) 字串
如下:#define add(a,b) (a)+(b)
那麼:程式中的 b=add((2*3),(4*5)) 等價於 b=(2*3)+(4*5) 。
具體請參考c語言書籍。
2。下面看:enterpwdn(0x7fff4);
會被替換成:((void (*)(int))0x00000020)(0x7fff4);
這個涉及到函式指標,函式指標的用法如下:
void fun(int x);
void(*pfun) (int x);
pfun=fun;
那麼呼叫函式fun可以這樣寫:a. fun(5); b. (*pfun)(5);
則:((void(*)(int))0x00000020)(0x7fff4);中藍色0x7fff4是傳遞的引數,紅色(void(*)(int))0x00000020是函式名。其實函式名本身就是乙個位址。像上式中,如果你知道函式fun存在位址0x012345,那麼理論上你可以這麼寫:0x012345(5),當然實際上不能這麼寫,因為你雖然fun在0x012345位址,但是你編譯器不知到這個函式的引數、返回值等資訊。所以要強制轉換一下。
如果把 char a ; 中的a轉換成 int 形變數,要這樣:b=(int)a;
同樣要把0x00000020位址轉換為函式名,也要強制轉換,只要在0x00000020的前面加上要轉換的型別。(void(*)(int))就是函式型別,和void (*pfun) (int x); // 宣告乙個函式指標 是相對應的。
3。再看一下enterpwdn(0x7fff4);呼叫之後具體的引數傳遞,這個涉及到c和彙編的相互呼叫。
看__entry
resetentry
b resethandler
b handlerundef ;handler forundefined mode
b handlerswi ;handler for swiinterrupt
b handlerpabort ;handler forpabort
b handlerdabort ;handler fordabort
b . ;reserved
b handlerirq ;handler for irqinterrupt
b handlerfiq ;handler for fiqinterrupt
;@0x20
b enterpwdn ; must be @0x20.
跳到0x00000020位址後會接著跳轉到標號enterpwdn 處。
enterpwdn
mov r2,r0 ;r2=rclkcon
tst r0,#0x8 ;sleep mode?
bne enter_sleep
看這裡第一句:mov r2,r0 。其實 r0中存的就是引數0x7fff4,這個涉及到c呼叫彙編,自己找一下參考書吧,我就不獻醜了。
arm中#define enterpwdn(clkcon) ((void(*)(int))0x20)(clkcon))代表什麼意思
1.首先,這是乙個帶引數巨集定義,所以,如果有語句enterpwdn(0x7fff4)則展開以後就是如下語句 ((void(*)(int))0x20)(0xffff4))
2.(void(*)(int))0x20的意思
(void(*)(int))作為乙個強制型別轉換,將0x20轉換為乙個函式指標型別,這個函式的原型為 voidfun(int); 而後面的0xffff4就是代表的函式的引數,所以 ((void(*)(int))0x20)(0xffff4))整句話的意思就是呼叫位址在0x20處的函式,引數為0xffff4.其實看後面實際上就是跳轉到位址0x20處執行**,並且把引數傳到r0,atpcs中規定1-4個引數對應的儲存暫存器為r0-r3。
3.再看在2440init.s中對該部分的定義
b resethandler
b handlerundef ;handler for undefined mode
b handlerswi ;handler for swi interrupt
b handlerpabort ;handler for pabort
b handlerdabort ;handler for dabort
b . ;reserved
b handlerirq ;handler for irq interrupt
b handlerfiq ;handler for fiq interrupt
;@0x20
b enterpwdn ; must be @0x20.
enterpwdn
mov r2,r0 ;r2=rclkcon
tst r0,#0x8 ;sleep mode?
bne enter_sleep
b enterpwdn ; must be @0x20.這條語句,對應的指令位址為0x20,這就是前面((void(*)(int))0x20)中0x20的意義,然後語句跳到enterpwdn執行,單然,引數值就傳給了r0,後面的東西檢視硬體說明。
函式 入口位址 返回位址
2009 07 30 17 41 44 分類 c語言學習 標籤 字型大小 大中小訂閱 陣列的名字代表的是陣列的首位址 函式的名字代表的就是函式的入口位址。可以列印一下 include void hello world void printf hello world n void hello baby...
python通過字串來呼叫函式
有時候我們想要通過字串來直接呼叫函式,方便通過輸入的引數來直接控制呼叫的函式 常規操作def function1 print function1 def function2 print function2 def function3 print function3 def call fun by s...
通過函式指標呼叫函式
指標可以不但可以指向乙個整形,浮點型,字元型,字串型的變數,也可以指向相應的陣列,而且還可以指向乙個函式。乙個函式在編譯的時候會被分配給乙個入口位址。這個函式入口位址稱為函式的指標。可以用乙個指標變數指向函式,然後通過該指標變數呼叫此函式。定義指向函式的指標變數的方法是 int p int int ...