<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > Keil C51 中的函數指針和再入函數

Keil C51 中的函數指針和再入函數

作者: 時(shí)間:2016-11-27 來(lái)源:網(wǎng)絡(luò ) 收藏

下面兩個(gè)源文件將解答這個(gè)問(wèn)題,使問(wèn)題容易明白。第一個(gè)源文件FPCALLER.C,包括一個(gè)函數,它通過(guò)一個(gè)函數指針(fptr)調用另一個(gè)函數。

voidfunc_caller(long (code *fptr) (unsigned int))

{

unsigned char i;

for(i=0;i<10;i++)

{

(*ftpr)(i);

}

}

第二個(gè)源文件FPMAIN.C,包含C主函數和被func_caller調用的函數func。注意main函數調用func_caller,把func的地址作為參數傳遞給func_caller。

extern void func_caller (long (code *) (unsigned int));

int func (unsigned int count)

{

long j;

long k;

k = 0;

for (j = 0; j < count; j++)

{

k += j;

}

return (k);

}

void main (void)

{

func_caller (func);

while (1) ;

}

上面的兩個(gè)的源文件編譯和鏈接都沒(méi)有錯誤。通過(guò)連接器,調用樹(shù)的映射文件如下:

SEGMENTDATA_GROUP

+--> CALLED SEGMENTSTARTLENGTH

-------------------------------------------------

?C_C51STARTUP----------

+--> ?PR?MAIN?FPMAIN

?PR?MAIN?FPMAIN----------

+--> ?PR?_FUNC?FPMAIN

+--> ?PR?_FUNC_CALLER?FPCALLER

?PR?_FUNC?FPMAIN0008H000AH

?PR?_FUNC_CALLER?FPCALLER0008H0003H

在這個(gè)簡(jiǎn)單的例子中,許多信息可以從調用樹(shù)里挖掘出來(lái)。?C_C51STARTUP段調用main函數的?PR?MAIN?FPMAIN,段名各部分解析:PR是代碼存儲區,MAIN是函數名,FPMAIN是定義函數所在的源文件名。

MAIN函數調用FUNC和FUNC_CALLER(根據調用樹(shù))。注意這是錯誤的。MAIN函數沒(méi)有調用FUNC函數,但是它傳遞FUNC函數的地址給FUNC_CALLER函數。同時(shí)注意,根據調用樹(shù)FUNC_CALLER沒(méi)有調用FUNC。這是因為FUNC_CALLER是通過(guò)函數指針間接調用FUNC。

FPMAIN文件中的FUNC函數使用從0008H開(kāi)始,長(cháng)000AH字節的數據。FPCALLER文件中的FUNC_CALLER函數也使用從0008H開(kāi)始,長(cháng)0003H字節的數據。這是重要的。

FUNC_CALLER函數使用的存儲區從0008H開(kāi)始,FUNC函數使用的存儲區也是從0008H開(kāi)始。因為FUNC_CALLER函數調用FUNC函數,又因為兩個(gè)函數使用相同的存儲區,這樣就產(chǎn)生了問(wèn)題。當FUNC函數被FUNC_CALLER函數調用時(shí),存儲區將被FUNC_CALLER破壞。這個(gè)問(wèn)題是怎樣產(chǎn)生的?是由Keil 51編譯器產(chǎn)生還是由連接器產(chǎn)生?

這個(gè)問(wèn)題的原因是函數指針。當你使用函數指針時(shí),你將總是遇到這樣的問(wèn)題。幸運的是,他們是容易被修改的。“OVERLAY”指令讓你指定在調用樹(shù)中,函數與其他函數是怎樣連接的。

為了修正上面顯示的調用樹(shù),FUNC函數必須從MAIN函數中刪除,同時(shí)FUNC函數必須插入到FUNC_CALLER函數中。下面用“OVERLAY”指令修改后如下:

OVERLAY (?PR?MAIN?FPMAIN ~ ?PR?_FUNC?FPMAIN,

?PR?_FUNC_CALLER?FPCALLER ! ?PR?_FUNC?FPMAIN)

為了刪除或插入相關(guān)的進(jìn)入調用樹(shù),指定第一調用和第二調用。“~”符號用于刪除相關(guān)的函數,“!”用于插入一個(gè)外部函數。例如?PR?MAIN?FPMAIN ~ ?PR?_FUNC?FPMAIN,意義是從MAIN函數中刪除FUNC函數的調用。

經(jīng)過(guò)調整連接命令,包括用“OVERLAY”指令修正調用樹(shù),調整后的映射文件如下:

SEGMENTDATA_GROUP

+--> CALLED SEGMENTSTARTLENGTH

-------------------------------------------------

?C_C51STARTUP----------

+--> ?PR?MAIN?FPMAIN

?PR?MAIN?FPMAIN----------

+--> ?PR?_FUNC_CALLER?FPCALLER

?PR?_FUNC_CALLER?FPCALLER0008H0003H

+--> ?PR?_FUNC?FPMAIN

?PR?_FUNC?FPMAIN000BH000AH

修正后的調用樹(shù)中,FUNC_CALLER函數和FUNC函數使用獨立存儲空間。

函數指針列表

下面是一個(gè)典型的函數指針列表的定義:

long (code *fp_tab []) (void) = { func1, func2, func3 };

如果你的MAIN函數中通過(guò)fp_tab調用歌函數,連接映射文件出現如下:

SEGMENTDATA_GROUP

+--> CALLED SEGMENTSTARTLENGTH

----------------------------------------------

?C_C51STARTUP----------

+--> ?PR?MAIN?FPT_MAIN

+--> ?C_INITSEG

?PR?MAIN?FPT_MAIN0008H0001H

?C_INITSEG----------

+--> ?PR?FUNC1?FP_TAB

+--> ?PR?FUNC2?FP_TAB

+--> ?PR?FUNC3?FP_TAB

?PR?FUNC1?FP_TAB0008H0008H

?PR?FUNC2?FP_TAB0008H0008H

?PR?FUNC3?FP_TAB0008H0008H

三個(gè)函數通過(guò)列表被調用,FUNC1,FUNC2 和FUNC3被C_INITSEG調用。但是這是錯誤的,C_INITSEG按照常規的方式在程序中初始化。這些函數被引入初始化代碼中,因為函數指針列表被初始化成這些函數的地址值。

注意這些變量(FUNC1,FUNC2 和FUNC13)和MAIN函數的起始地址都是0008H。這樣不能正常工作,因為MAIN函數調用FUNC1,FUNC2 和FUNC3(通過(guò)函數指針類(lèi)表)。

C51編譯器和BL51連接器聯(lián)合工作,當使用函數指針列表時(shí),使得函數變量空間覆蓋很容易。但是,你必須合理的聲明指針列表。如果你這樣做了,就可以避免使用“OVERLAY”指令。下面的函數指針列表的定義,C51和BL51可以自動(dòng)處理:

code long (code *fp_tab []) (void) = { func1, func2, func3 };

注意唯一不同的是存儲列表在CODE空間?,F在,連接映射文件如下:

SEGMENTDATA_GROUP

+--> CALLED SEGMENTSTARTLENGTH

----------------------------------------------

?C_C51STARTUP----------

+--> ?PR?MAIN?FPT_MAIN

?PR?MAIN?FPT_MAIN0008H0001H

+--> ?CO?FP_TAB

?CO?FP_TAB----------

+--> ?PR?FUNC1?FP_TAB

+--> ?PR?FUNC2?FP_TAB

+--> ?PR?FUNC3?FP_TAB

?PR?FUNC1?FP_TAB0009H0008H

?PR?FUNC2?FP_TAB0009H0008H

?PR?FUNC3?FP_TAB0009H0008H

現在,初始化代碼中沒(méi)有引入FUNC1,FUNC2 和FUNC3。但是,MAIN函數中引入一個(gè)常數段FP_TAB。這是一個(gè)函數指針列表。因為函數指針列表引入了FUNC1,FUNC2 和FUNC3,所以調用樹(shù)是正確的。

只要把函數指針列表放在一個(gè)獨立的源文件中,在調用樹(shù)中,C51和BL51就能正確的連接。



關(guān)鍵詞: KeilC51函數指針再入函

評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>