真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

c語(yǔ)言函數(shù)入棧 c++入棧函數(shù)

C語(yǔ)言函數(shù)調(diào)用棧

程序的執(zhí)行過程可看作連續(xù)的函數(shù)調(diào)用。當(dāng)一個(gè)函數(shù)執(zhí)行完畢時(shí),程序要回到調(diào)用指令的下一條指令(緊接call指令)處繼續(xù)執(zhí)行。函數(shù)調(diào)用過程通常使用堆棧實(shí)現(xiàn),每個(gè)用戶態(tài)進(jìn)程對(duì)應(yīng)一個(gè)調(diào)用棧結(jié)構(gòu)(call stack)。編譯器使用堆棧傳遞函數(shù)參數(shù)、保存返回地址、臨時(shí)保存寄存器原有值(即函數(shù)調(diào)用的上下文)以備恢復(fù)以及存儲(chǔ)本地局部變量。

從策劃到設(shè)計(jì)制作,每一步都追求做到細(xì)膩,制作可持續(xù)發(fā)展的企業(yè)網(wǎng)站。為客戶提供成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、網(wǎng)站策劃、網(wǎng)頁(yè)設(shè)計(jì)、申請(qǐng)域名、網(wǎng)頁(yè)空間、網(wǎng)絡(luò)營(yíng)銷、VI設(shè)計(jì)、 網(wǎng)站改版、漏洞修補(bǔ)等服務(wù)。為客戶提供更好的一站式互聯(lián)網(wǎng)解決方案,以客戶的口碑塑造優(yōu)易品牌,攜手廣大客戶,共同發(fā)展進(jìn)步。

不同處理器和編譯器的堆棧布局、函數(shù)調(diào)用方法都可能不同,但堆棧的基本概念是一樣的。

寄存器是處理器加工數(shù)據(jù)或運(yùn)行程序的重要載體,用于存放程序執(zhí)行中用到的數(shù)據(jù)和指令。因此函數(shù)調(diào)用棧的實(shí)現(xiàn)與處理器寄存器組密切相關(guān)。

AX(AH、AL):累加器。有些指令約定以AX(或AL)為源或目的寄存器。輸入/輸出指令必須通過AX或AL實(shí)現(xiàn),例如:端口地址為43H的內(nèi)容讀入CPU的指令為INAL,43H或INAX,43H。目的操作數(shù)只能是AL/AX,而不能是其他的寄存器。 [5]

BX(BH、BL): 基址寄存器 。BX可用作間接尋址的地址寄存器和 基地址寄存器 ,BH、BL可用作8位通用數(shù)據(jù)寄存器。 [5]

CX(CH、CL):計(jì)數(shù)寄存器。CX在循環(huán)和串操作中充當(dāng)計(jì)數(shù)器,指令執(zhí)行后CX內(nèi)容自動(dòng)修改,因此稱為計(jì)數(shù)寄存器。 [5]

DX(DH、DL):數(shù)據(jù)寄存器。除用作通用寄存器外,在 I/O指令 中可用作端口 地址寄存器 ,乘除指令中用作輔助累加器。 [5]

2.指針和 變址寄存器

BP( Base Pointer Register):基址指針寄存器。 [5]

SP( Stack Pointer Register): 堆棧指針寄存器 。 [5]

SI( Source Index Register):源變址寄存器。 [5]

DI( Destination Index Register):目的變址寄存器。 [5]

函數(shù)調(diào)用棧的典型內(nèi)存布局如下圖所示:

圖中給出主調(diào)函數(shù)(caller)和被調(diào)函數(shù)(callee)的棧幀布局,"m(%ebp)"表示以EBP為基地址、偏移量為m字節(jié)的內(nèi)存空間(中的內(nèi)容)。該圖基于兩個(gè)假設(shè):第一,函數(shù)返回值不是結(jié)構(gòu)體或聯(lián)合體,否則第一個(gè)參數(shù)將位于"12(%ebp)" 處;第二,每個(gè)參數(shù)都是4字節(jié)大小(棧的粒度為4字節(jié))。在本文后續(xù)章節(jié)將就參數(shù)的傳遞和大小問題做進(jìn)一步的探討。 此外,函數(shù)可以沒有參數(shù)和局部變量,故圖中“Argument(參數(shù))”和“Local Variable(局部變量)”不是函數(shù)棧幀結(jié)構(gòu)的必需部分。

其中,主調(diào)函數(shù)將參數(shù)按照調(diào)用約定依次入棧(圖中為從右到左),然后將指令指針EIP入棧以保存主調(diào)函數(shù)的返回地址(下一條待執(zhí)行指令的地址)。進(jìn)入被調(diào)函數(shù)時(shí),被調(diào)函數(shù)將主調(diào)函數(shù)的幀基指針EBP入棧,并將主調(diào)函數(shù)的棧頂指針ESP值賦給被調(diào)函數(shù)的EBP(作為被調(diào)函數(shù)的棧底),接著改變ESP值來為函數(shù)局部變量預(yù)留空間。此時(shí)被調(diào)函數(shù)幀基指針指向被調(diào)函數(shù)的棧底。以該地址為基準(zhǔn),向上(棧底方向)可獲取主調(diào)函數(shù)的返回地址、參數(shù)值,向下(棧頂方向)能獲取被調(diào)函數(shù)的局部變量值,而該地址處又存放著上一層主調(diào)函數(shù)的幀基指針值。本級(jí)調(diào)用結(jié)束后,將EBP指針值賦給ESP,使ESP再次指向被調(diào)函數(shù)棧底以釋放局部變量;再將已壓棧的主調(diào)函數(shù)幀基指針彈出到EBP,并彈出返回地址到EIP。ESP繼續(xù)上移越過參數(shù),最終回到函數(shù)調(diào)用前的狀態(tài),即恢復(fù)原來主調(diào)函數(shù)的棧幀。如此遞歸便形成函數(shù)調(diào)用棧。

EBP指針在當(dāng)前函數(shù)運(yùn)行過程中(未調(diào)用其他函數(shù)時(shí))保持不變。在函數(shù)調(diào)用前,ESP指針指向棧頂?shù)刂?,也是棧底地址。在函?shù)完成現(xiàn)場(chǎng)保護(hù)之類的初始化工作后,ESP會(huì)始終指向當(dāng)前函數(shù)棧幀的棧頂,此時(shí),若

c語(yǔ)言函數(shù)參數(shù)入棧順序

從右向左;

例如:f(int a, int b, int c)

c先入棧,然后b,其次a;

C語(yǔ)言 入棧順序?yàn)槭裁春瘮?shù)入棧順序從右往左

C語(yǔ)言函數(shù)參數(shù)入棧順序從右到左是為了方便可變參數(shù)函數(shù)。

一、在函數(shù)調(diào)用時(shí),函數(shù)參數(shù)的傳遞,在C語(yǔ)言中是通過棧數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的。

在調(diào)用函數(shù)時(shí),先根據(jù)調(diào)用函數(shù)使用的參數(shù),自右向左依次壓入棧中,然后調(diào)用函數(shù),在函數(shù)開始執(zhí)行時(shí),將參數(shù)再依次彈棧。根據(jù)棧數(shù)據(jù)結(jié)構(gòu)先進(jìn)后出的特點(diǎn),在函數(shù)中彈棧的順序就是從左向右的。

二、對(duì)于參數(shù)固定的函數(shù),無論是從左向右還是從右向左,都沒什么區(qū)別,最終都是所有參數(shù)全部傳遞。

三、對(duì)于可變參數(shù),比如printf,會(huì)在第一個(gè)參數(shù)格式字符串中,指明后續(xù)有幾個(gè)參數(shù),各自是什么類型的。于是在函數(shù)中,參數(shù)格式字符串必須第一個(gè)彈棧,否則無法獲取參數(shù)類型,也就無法獲知后續(xù)參數(shù)占幾個(gè)字節(jié),導(dǎo)致無法正確獲知參數(shù)。

四、理論上來說,如果從左向右壓棧,可變參數(shù)標(biāo)記格式字符串的參數(shù)放在最后,那么也是可以的。 不過最早設(shè)計(jì)C語(yǔ)言的人采用了這種方式,后續(xù)也就延續(xù)下來了。

用C語(yǔ)言編寫函數(shù)實(shí)現(xiàn)順序棧的進(jìn)棧、退棧、取棧頂?shù)乃惴ā?/h2>

#includestdio.h

#define stacksize 100 //假定預(yù)分配的??臻g最多為100 個(gè)元素

typedef char elementtype; //假定棧元素的數(shù)據(jù)類型為字符 ,在此處可以自行設(shè)置

typedef struct

{

elementtype data[stacksize];

int top;

}seqstack;

// 置空棧

void initstack(seqstack *s)

{

s-top=-1;

//解釋一下,s-top 指向的是當(dāng)前棧頂元素的位置

//當(dāng)要向棧中添加一個(gè)新元素時(shí),要先將s-top增加1,

//此時(shí)s-top 指向的就是新元素要添加的位置了。

//所以當(dāng)棧為空時(shí),填加第一元素時(shí),top加1 后

//s-top的值就變?yōu)?,也就是第一個(gè)元素的位置了。

}

//判???/p>

int stackempty(seqstack *s)

{

if(s-top==-1)

return 1; //若相等就返回1,否則為0

else return 0;

}

//入棧

void push(seqstack *s,elementtype x)

{

if(s-top==stacksize -1 ) //進(jìn)棧前判斷棧是否已經(jīng)滿了

printf(" stack overflow\n");

else

{

s-top= s-top + 1;

s-data[s-top]=x;

}

}

//出棧

elementtype pop(seqstack *s)

{

if(stackempty(s)) //出棧前先判斷當(dāng)前棧中是否有內(nèi)容

printf("stack is empty\n");

else

{

return s-data[s-top--]; //出棧后s-top的值會(huì)自減1

}

}

//取棧頂元素(只是想知道棧頂?shù)闹?,并沒有出棧)

elementtype gettop(seqstack *s)

{

if(stackempty(s))

{

printf("stack already empty.\n");

}

else return s-data[s-top];

}

int main()

{

elementtype x;

seqstack *s; //定義一個(gè)棧,用指針的方式定義的

initstack(s); //想初始化定義好的棧

//當(dāng)棧為空時(shí)調(diào)用出棧操作

pop(s);

//向棧中添加一個(gè)元素a

push(s,'a');

//觀察此時(shí)的棧頂元素

x=gettop(s);

printf("%c\n",x);

//再添加一個(gè)元素b

push(s,'b');

//觀察此時(shí)的棧頂元素

x=gettop(s);

printf("%c\n",x);

//彈出棧頂?shù)脑?/p>

x=pop(s);

printf("%c\n",x);

//觀察彈出后棧頂元素的變化情況

x=gettop(s);

printf("%c\n",x);

return 0;

}


網(wǎng)頁(yè)題目:c語(yǔ)言函數(shù)入棧 c++入棧函數(shù)
文章地址:http://weahome.cn/article/ddgoihi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部