久久婷婷香蕉热狠狠综合,精品无码国产自产拍在线观看蜜,寡妇房东在做爰3,中文字幕日本人妻久久久免费,国产成人精品三上悠亚久久

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > C語言中入棧順序與變量輸出(chu)

C語(yu)言中入(ru)棧順序與變量輸(shu)出 時(shi)間:2018-09-29  ;    來源:未知

1).內存區域(yu)劃分:

圖1 程序運行時(shi)的內存(cun)區域

如圖所示:C程序中,棧區主要存儲函數的參數,局部(bu)變量等,并且棧底為高地(di)(di)址,棧頂為低地(di)(di)址(如圖:由高地(di)(di)址向低地(di)(di)址擴展)。

2).入棧順序:

A:函數參數的入棧(zhan)順序(xu):自(zi)右向左(zuo)

原因:

函(han)數參(can)(can)數的(de)(de)入棧(zhan)(zhan)(zhan)(zhan)順(shun)序和具體編譯器的(de)(de)實(shi)現(xian)有關。有些(xie)參(can)(can)數是(shi)從左(zuo)向(xiang)右入棧(zhan)(zhan)(zhan)(zhan),如(ru):Pascal語言從左(zuo)到右入棧(zhan)(zhan)(zhan)(zhan)(不支持變參(can)(can)),被調用者清棧(zhan)(zhan)(zhan)(zhan);有些(xie)語言還可(ke)以通(tong)過修飾符進行指(zhi)定,如(ru):Visual C++;但(dan)是(shi)C語言(cdecl)采用自(zi)右向(xiang)左(zuo)的(de)(de)方式(shi)入棧(zhan)(zhan)(zhan)(zhan),調用者清棧(zhan)(zhan)(zhan)(zhan)。

這是因為自(zi)右向左(zuo)入(ru)棧(zhan)(zhan)順序(xu)的好處(chu)就(jiu)是可(ke)(ke)(ke)以動態的變(bian)化(hua)參(can)(can)數(shu)(shu)個(ge)數(shu)(shu)。通(tong)過堆棧(zhan)(zhan)分析可(ke)(ke)(ke)知(zhi),自(zi)左(zuo)向右入(ru)棧(zhan)(zhan)方式(shi)中,前面(mian)的參(can)(can)數(shu)(shu)會被壓(ya)入(ru)棧(zhan)(zhan)底。除非知(zhi)道參(can)(can)數(shu)(shu)個(ge)數(shu)(shu),否則無(wu)法通(tong)過棧(zhan)(zhan)指針的相對位移求得左(zuo)邊(bian)的參(can)(can)數(shu)(shu)。這樣就(jiu)無(wu)法實(shi)(shi)現可(ke)(ke)(ke)變(bian)參(can)(can)數(shu)(shu)。因此,C語言采(cai)用自(zi)右向左(zuo)入(ru)棧(zhan)(zhan)順序(xu),主要是因為實(shi)(shi)現可(ke)(ke)(ke)變(bian)長參(can)(can)數(shu)(shu)形式(shi)(如:printf函數(shu)(shu))。可(ke)(ke)(ke)變(bian)長參(can)(can)數(shu)(shu)主要通(tong)過第(di)一個(ge)定參(can)(can)數(shu)(shu)來確定參(can)(can)數(shu)(shu)列(lie)(lie)表,所以自(zi)右向左(zuo)入(ru)棧(zhan)(zhan)后,函數(shu)(shu)調用時棧(zhan)(zhan)頂指針指向的就(jiu)是參(can)(can)數(shu)(shu)列(lie)(lie)表的第(di)一個(ge)確定參(can)(can)數(shu)(shu),這樣就(jiu)可(ke)(ke)(ke)以了。

例子1:

#include <stdio.h>

void print(int x, int y, int z)

{

printf("x = %d addr %p\n", x, &x);

printf(&quot;y = %d addr %p\n", y, &y);

printf("z = %d addr %p\n", z, &amp;z);

}

 

int main()

{

print(1,2,3);//自右(you)向入壓棧

return 0;

}

 

運行結果:

x = 1 addr 0xbfb5c760 //棧頂,后壓棧

y = 2 addr 0xbfb5c764

z = 3 addr 0xbfb5c768 //棧底(di),先入棧

B:局部(bu)變量(liang)的入棧(zhan)順(shun)序:

在(zai)沒有(you)棧溢(yi)出保護機制下編譯時,所有(you)局(ju)部變(bian)量按(an)系統為局(ju)部變(bian)量申(shen)(shen)(shen)請(qing)內存中(zhong)棧空間的順(shun)(shun)序,即(ji):先申(shen)(shen)(shen)請(qing)哪個(ge)變(bian)量,哪個(ge)先入棧,正向的。也(ye)就是說,編譯器(qi)給變(bian)量空間的申(shen)(shen)(shen)請(qing)是直接按(an)照(zhao)變(bian)量申(shen)(shen)(shen)請(qing)順(shun)(shun)序執(zhi)行的。(見例子2)

在有棧(zhan)溢(yi)出(chu)保(bao)護機制下編譯時(shi),入棧(zhan)順序有所改變(bian),先按(an)照(zhao)(zhao)類型(xing)(xing)劃分,再按(an)照(zhao)(zhao)定義變(bian)量的(de)先后順序劃分,即:char型(xing)(xing)先申請(qing),int類型(xing)(xing)后申請(qing)(與編譯器溢(yi)出(chu)保(bao)護時(shi)的(de)規定相關);然后棧(zhan)空間的(de)申請(qing)順序與代碼中變(bian)量定義順序相反(后定義的(de)先入棧(zhan))。(見例子(zi)2)

例子2:stack.c

#include <stdio.h>

 

int main()

{

int a[5] = {1,2,3,4,5};

int b[5] = {6,7,8,9,10};

char buf1[6] = "abcde";

char buf2[6] = "fghij";

int m = -1;

int n = -2;

printf("a[0]  = %3d, addr: %p\n", a[0], &a[0]);

printf("a[4]  = %3d, addr: %p\n", a[4], &a[4]);

printf("b[0]  = %3d, addr: %p\n", b[0], &b[0]);

printf("b[4]  = %3d, addr: %p\n", b[4], &b[4]);

printf("buf1[0] = %3d, addr: %p\n", buf1[0], &buf1[0]);

printf("buf1[5] = %3d, addr: %p\n", buf1[5], &buf1[5]);

printf("buf2[0] = %3d, addr: %p\n", buf2[0], &buf2[0]);

printf("buf2[5] = %3d, addr: %p\n", buf2[5], &amp;buf2[5]);

printf("m  = %3d, addr: %p\n", m, &m);

printf("n  = %3d, addr: %p\n", n, &n);

}

沒有棧溢出保護機制下的編譯:

$ gcc stack.c -g -o stack -fno-stack-pprotector

$ ./stack

a[0]  =   1, addr: 0xbfa5185c //數組(zu)內部,地址由低到高不變

a[4]  =   5, addr: 0xbfa5186c //棧底(di),高地(di)址(zhi)

b[0]  =   6, addr: 0xbfa51848

b[4]  =  10, addr: 0xbfa51858

buf1[0] =  97, addr: 0xbfa51842

buf1[5] =   0, addr: 0xbfa51847

buf2[0] = 102, addr: 0xbfa5183c

buf2[5] =   0, addr: 0xbfa51841

=  -1, addr: 0xbfa51838

=  -2, addr: 0xbfa51834  //棧(zhan)頂(ding),低地址

可以看出入棧順序:a -> b -> buf1 -> buf2 -> m -> n(先定義,先壓棧)

 

棧(zhan)溢出保護機(ji)制下的編譯:

$ gcc stack.c -g -o stack

$ ./stack

a[0]  =   1, addr: 0xbfc69130 //棧頂

a[4]  =   5, addr: 0xbfc69140

b[0]  =   6, addr: 0xbfc69144

b[4]  =  10, addr: 0xbfc69154 

buf1[0] =  97, addr: 0xbfc69160 //char類型,優先入棧

buf1[5] =   0, addr: 0xbfc69165

buf2[0] = 102, addr: 0xbfc69166

buf2[5] =   0, addr: 0xbfc6916b //棧底(di)

=  -1, addr: 0xbfc69158

=  -2, addr: 0xbfc6915c //int類(lei)型,后壓(ya)棧

 

可以看(kan)出入棧(zhan)順序:buf2 -> buf1 -> n -> m -> b -> a(char類型先(xian)入棧(zhan),int類型后(hou)入棧(zhan);先(xian)定義,后(hou)壓棧(zhan))

3).指(zhi)針越界輸出:

例子3:stack1.c

#include <stdio.h>

 

int main()

{

char buf1[6] = "abcef";

char buf2[6] = "fghij";

int a[5] = {1,2,3,4,5};

int b[5] = {6,7,8,9,10};

int m = -1;

int n = -2;

char *p = &buf2[0];

printf("a[0]  = %3d, addr: %p\n", a[0], &a[0]);

printf("a[4]  = %3d, addr: %p\n", a[4], &a[4]);

printf("b[0]  = %3d, addr: %p\n", b[0], &b[0]);

printf("b[4]  = %3d, addr: %p\n", b[4], &b[4]);

printf("buf1[0] = %3d, addr: %p\n", buf1[0], &buf1[0]);

 printf("buf1[5] = %3d, addr: %p\n", buf1[5], &buf1[5]);

printf("buf2[0] = %3d, addr: %p\n", buf2[0], &buf2[0]);

printf("buf2[5] = %3d, addr: %p\n", buf2[5], &buf2[5]);

printf("m  = %3d, addr: %p\n", m, &m);

printf("n = %3d, addr: %p\n", n, &n);

printf("p[0]  = %3d, addr: %p\n", p[0], &p[0]);

printf("p[6]  = %3d, addr: %p\n", p[6], &p[6]);

printf("p[-6]  = %3d, addr: %p\n", p[-6], &p[-6]);

printf("p[-42]  = %3d, addr: %p\n", p[-42], &p[-42]);

printf("p[-43]  = %3d, addr: %p\n", p[-43], &p[-43]);

printf("p[-53]  = %3d, addr: %p\n", p[-53], &p[-53]);

printf("p[-54]  = %3d, addr: %p\n", p[-54], &p[-54]);

printf("p[-55]  = %3d, addr: %p\n", p[-55], &p[-55]);

printf("p[-56]  = %3d, addr: %p\n", p[-56], &p[-56]);

printf("p[-57]  = %3d, addr: %p\n", p[-57], &p[-57]);

printf("p[-58]  = %3d, addr: %p\n", p[-58], &p[-58]);

printf("p[-59]  = %3d, addr: %p\n", p[-59], &p[-59]);

}

棧(zhan)溢出保(bao)護機制下的編譯:

$ gcc stack1.c -g -o stack1

$ ./stack1

a[0]  =   1, addr: 0xbff5ab6c //棧頂(ding),0xbff5ab6c,低地址

a[4]  =   5, addr: 0xbff5ab7c

b[0]  =   6, addr: 0xbff5ab80

b[4]  =  10, addr: 0xbff5ab90

buf1[0] =  97, addr: 0xbff5aba0 //&amp;p[-6]

buf1[5] =   0, addr: 0xbff5aba5

buf2[0] = 102, addr: 0xbff5aba6 //&p[0]

buf2[5] =   0, addr: 0xbff5abab //棧底,0xbff5abab,高(gao)地址--->&p[6]:越界,值隨機

=  -1, addr: 0xbff5ab94

=  -2, addr: 0xbff5ab98

p[0]  = 102, addr: 0xbff5aba6 //&buf2[0]

p[6]  =   0, addr: 0xbff5abac //&buf2[6],越界,無初始值,值隨機(ji)

p[-6]  =  97, addr: 0xbff5aba0 //&buf1[0],越(yue)界,已有初始值,buf1[0],p[-6]為97

p[-42]  =   5, addr: 0xbff5ab7c //&a[4]

p[-43]  =   0, addr: 0xbff5ab7b //&a[4] - 1字節,大小0x00 = 0

p[-53]  =   0, addr: 0xbff5ab71 //&a[1] + 1字節,大小0x00 = 0

p[-54]  =   2, addr: 0xbff5ab70 //&a[1]

p[-55]  =   0, addr: 0xbff5ab6f //p[-55]到(dao)p[-58]能(neng)看(kan)出Linux是小(xiao)端存儲。

p[-56]  =   0, addr: 0xbff5ab6e //小端存(cun)儲:低(di)地址(zhi)存(cun)低(di)位(wei)(wei),高地址(zhi)存(cun)高位(wei)(wei)

p[-57]  =   0, addr: 0xbff5ab6d //a[0]=1,即:0x01 0x00 0x00 0x00(低位(wei)到高位(wei))

p[-58]  =   1, addr: 0xbff5ab6c //&a[0]

p[-59]  =   -65, addr: 0xbff5ab6b //&a[0] - 1字節,越界(jie),無(wu)初始值,值隨機

入棧(zhan)(zhan)順序:(棧(zhan)(zhan)底:高地址(zhi))buf2 -> buf1 -> n -> m -> b -> a[4] -> a[0](棧(zhan)(zhan)頂:低地址(zhi))

&;p[6]--&amp;p[0]--&p[-6]--------------&p[-42]--&p[-58]--&p[-59]

問題:指針(zhen)p越界會出現(xian)問題,如果在p[-6] = 'k';那么會導致因越界覆蓋內存里面buf1[0]的值。

上一篇:ZigBee的組網流程圖

下一篇:Linux下Samba服務器的安裝與配置(簡單實用)

熱(re)點文章推(tui)薦
華清學員就業榜單
高薪學員(yuan)經驗分享
熱點(dian)新聞推薦
前臺(tai)專線:010-82525158 企業培訓(xun)洽談專線(xian):010-82525379 院校合(he)作洽談專(zhuan)線:010-82525379 Copyright © 2004-2022 北京華清遠見科技集團有限公司 版權所有 ,,京公海網安備11010802025203號

回到頂部