新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Keil C51 中的函數(shù)指針和再入函數(shù)

Keil C51 中的函數(shù)指針和再入函數(shù)

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

函數(shù)指針是C語(yǔ)言中幾個(gè)難點(diǎn)之一。由于8051的C編譯器的獨(dú)特要求,函數(shù)指針和再入函數(shù)有更多的挑戰(zhàn)需要克服。主要由于函數(shù)變量的傳遞。

本文引用地址:http://2s4d.com/article/201611/322385.htm

典型的(絕大部分8051芯片)函數(shù)變量通過(guò)堆棧的入棧和出棧命令來(lái)傳遞。因?yàn)?051只有有限的堆??臻g(128字節(jié)或更少的64字節(jié)),函數(shù)變量必須通過(guò)不同的方式進(jìn)行傳遞。

8051的PL/M-51編譯器,介紹在固定的存儲(chǔ)空間存儲(chǔ)變量的方式。當(dāng)使用連接器時(shí),程序建立一個(gè)調(diào)用樹(shù),計(jì)算出函數(shù)變量的互斥空間,然后覆蓋它們。這就是連接器的“OVERLAY”指令。

因?yàn)镻L/M-51不支持函數(shù)指針,所以不能實(shí)現(xiàn)間接函數(shù)調(diào)用。然而,C語(yǔ)言中存在這樣的問(wèn)題。連接器知道哪塊空間用于存儲(chǔ)間接函數(shù)的變量。怎樣間接加入函數(shù)進(jìn)入調(diào)用樹(shù)?

本文解釋在C51編程中,怎樣有效使用函數(shù)指針。特別地,討論如下幾個(gè)話題:

分配常量地址給一個(gè)指針;

定義函數(shù)指針;

C51中函數(shù)指針問(wèn)題;

使用OVERLAY指令確定調(diào)用樹(shù);

再入函數(shù)的指針;

固定地址的指針

你很容易的給函數(shù)指針?lè)峙湟粋€(gè)數(shù)字地址。有許多原因需要這樣做。例如,你需要復(fù)位目標(biāo)。你可以設(shè)置函數(shù)指針為0000H去實(shí)現(xiàn)。

你可以使用標(biāo)準(zhǔn)C語(yǔ)言的類型映射特點(diǎn),映射0X0000指針指向地址0的函數(shù)。例如,當(dāng)你編譯如下C代碼….

((void (code *) (void))0x0000) ();

…編譯器產(chǎn)生如下如下代碼:

;FUNCTION main (BEGIN)

;SOURCELINE#3

0000120000LCALL00H

;SOURCELINE#4

000322RET

; FUNCTION main (END)

這正是我們期望的:LCALL0

把一個(gè)數(shù)字常量映射成一個(gè)函數(shù)指針是一件很復(fù)雜的事情。下面關(guān)于上面的函數(shù)調(diào)用的各部分的描述,將幫助你怎樣更好的使用它們。

在上面的函數(shù)調(diào)用中,(void ( *) (void))是數(shù)據(jù)類型:一個(gè)不帶參數(shù)且返回void的函數(shù)指針。

0x0000是一個(gè)映射地址。經(jīng)過(guò)類型映射,函數(shù)指針指向地址0x0000。注意我們把一個(gè)圓括號(hào)放在數(shù)據(jù)類型和0x0000后面。如果我們僅僅想映射0x0000成為函數(shù)指針,這是不必要的。然而,因?yàn)槲覀儗⒁眠@個(gè)函數(shù),這些圓括號(hào)是必要的。

映射一個(gè)數(shù)值常量成為指針和通過(guò)指針調(diào)用函數(shù)是不同的。為了實(shí)現(xiàn)這個(gè),我們必須指定一個(gè)變量表。這就是為什么在此行的后面有一個(gè)()。

注意上面表達(dá)式中的所有圓括號(hào)都是必須的。分組和優(yōu)先級(jí)是很重要的。

上面不帶參數(shù)的函數(shù)指針和帶參數(shù)的函數(shù)指針的唯一不同是數(shù)據(jù)類型和變量列表。例如,下面的函數(shù)調(diào)用…..

((long (code *) (int int int ) 0x8000)(1,2,3);

聲明一個(gè)函數(shù),地址在0x8000,接收3個(gè)int型參數(shù),返回long型結(jié)果。

不帶參數(shù)的函數(shù)指針

指向函數(shù)的函數(shù)指針是可變的。函數(shù)的地址是一個(gè)可變的數(shù)值。例如,下面的函數(shù)指針的聲明….

void (*function_ptr) (void);

是一個(gè)調(diào)用function_ptr的指針。使用下面的代碼調(diào)用function_ptr函數(shù)。

(*function_ptr ) ();

因?yàn)楹瘮?shù)沒(méi)有參數(shù)傳送,所以參數(shù)列表時(shí)空的。

當(dāng)定義變量的時(shí)候,函數(shù)指針可以被分配地址:void (*function_ptr) (void) = another_fuction;或者在程序執(zhí)行過(guò)程中被分配,function_ptr = another_fuction;

注意,必須分配一個(gè)地址給函數(shù)指針。如果沒(méi)有分配,函數(shù)指針將有一個(gè)0值(如果你運(yùn)氣好),或者有一些你完全不知道的數(shù)值,依賴于你的數(shù)據(jù)存儲(chǔ)區(qū)的使用情況。當(dāng)你間接的調(diào)用一個(gè)函數(shù)通過(guò)函數(shù)指針,如果函數(shù)指針沒(méi)有初始化,你的程序?qū)⑹腔靵y的。

為了聲明一個(gè)帶返回值的函數(shù)指針,在聲明過(guò)程中你必須指定返回值的數(shù)據(jù)類型。例如,下面的聲明改變了上面的函數(shù)指針的聲明,返回一個(gè)float 數(shù)據(jù)。

float(*function_ptr) (void) = another_fuction;

帶參數(shù)的函數(shù)指針

帶參數(shù)的函數(shù)指針與不帶參數(shù)的函數(shù)指針是相似的。例如:

void (*function_ptr) (int, long,char); 一個(gè)函數(shù)指針,帶一個(gè)int參數(shù),帶一個(gè)long參數(shù),帶一個(gè)char參數(shù)。使用下面的代碼調(diào)用函數(shù)。

(*function_ptr) (12, 34L,‘A’);

注意,函數(shù)指針僅僅可以指向小于等于3個(gè)參數(shù)的函數(shù)。這是因?yàn)?,間接調(diào)用函數(shù)時(shí),參數(shù)必須保存在寄存器中。關(guān)于超過(guò)3個(gè)參數(shù)的函數(shù)指針的信息,在再入函數(shù)中介紹。

使用函數(shù)指針的附加說(shuō)明

如果你在C51中使用函數(shù)指針編程,有幾個(gè)附加的說(shuō)明你必須注意。

參數(shù)列表的限制

通過(guò)函數(shù)指針傳遞參數(shù)給函數(shù)必須把所有的參數(shù)存入寄存器。在大部分情況下,3個(gè)參數(shù)能夠自動(dòng)通過(guò)寄存器傳遞。在C51的用戶手冊(cè)中能找到傳遞參數(shù)進(jìn)入寄存器的運(yùn)算法則。但是并不保證,任何的3個(gè)數(shù)據(jù)類型可以傳遞。

因?yàn)镃51在寄存器中傳遞3個(gè)參數(shù),用于傳遞參數(shù)的存儲(chǔ)空間是不被分配的,除非函數(shù)指向一個(gè)要求更多參數(shù)的函數(shù)。如果在那樣的情況下,可以把參數(shù)混入一個(gè)結(jié)構(gòu)體中,然后通過(guò)一個(gè)結(jié)構(gòu)體指針傳遞參數(shù)。如果這樣不可接受,你可以使用再入函數(shù)(看下面)。

調(diào)用樹(shù)的保存

C51不把函數(shù)參數(shù)壓棧(除非使用再入函數(shù))。函數(shù)參數(shù)和全局變量被存入寄存器或固定的存儲(chǔ)空間。這樣阻止函數(shù)的再入。例如,一個(gè)函數(shù)調(diào)用它自己,它將覆蓋它自己的參數(shù)或存儲(chǔ)空間。函數(shù)的再入問(wèn)題通過(guò)關(guān)鍵字“reentrant”來(lái)解決。函數(shù)指針的非再入函數(shù)的副作用,在執(zhí)行中出現(xiàn)問(wèn)題。

為了保護(hù)盡量多的數(shù)據(jù)空間,連接器執(zhí)行調(diào)用樹(shù)的性能分析,決定一些存儲(chǔ)空間被安全的覆蓋。例如,如果你的應(yīng)用中包含main 函數(shù),函數(shù)a,函數(shù)b,函數(shù)c,并且main函數(shù)調(diào)用a,b,c,但是a,b,c之間沒(méi)有互相調(diào)用。在你應(yīng)用中的調(diào)用樹(shù)見(jiàn)出現(xiàn)如下:

MAIN

+→ A

+→ B

+→ C

這樣A,B,C的存儲(chǔ)空間可以被安全的覆蓋。

當(dāng)調(diào)用樹(shù)不能正確的建立,函數(shù)指針將帶來(lái)問(wèn)題。因?yàn)檫B接器不能決定函數(shù)之間的引用。在這個(gè)問(wèn)題上,沒(méi)有自動(dòng)的解決方法。


上一頁(yè) 1 2 3 下一頁(yè)

評(píng)論


技術(shù)專區(qū)

關(guān)閉