4編譯原理,陳意云,課后答案4_第1頁(yè)
4編譯原理,陳意云,課后答案4_第2頁(yè)
4編譯原理,陳意云,課后答案4_第3頁(yè)
4編譯原理,陳意云,課后答案4_第4頁(yè)
4編譯原理,陳意云,課后答案4_第5頁(yè)
已閱讀5頁(yè),還剩39頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

編譯原理習(xí)題課(4)2023/7/314編譯原理,陳意云,課后答案46.1使用Pascal的作用域規(guī)則,確定下面程序中用于名字a,b的每個(gè)出現(xiàn)的聲明。程序輸出整數(shù)1,2,3,4 programa(inputoutput);

procedureb(u,v,x,y:integer);

vara:recorda,b:integerend;

b:recordb,a:integerend;

begin

withadobegina:=u;b:=vend;

withbdobegina:=x;b:=yend;

writeln(a.a,a.b,b.a,b.b)

end;

begin

b(1,2,3,4)

end.2023/7/3124編譯原理,陳意云,課后答案46.1(續(xù))witha a—record

a:=u a—a.a

b:=v b—a.b

withb b—record

a:=x a—b.a

b:=y b—b.b2023/7/3134編譯原理,陳意云,課后答案46.2考慮下面的C程序

main(){

char*cp1,*cp2;

cp1=“12345”;

cp2=“abcdefghij”;

strcpy(cp1,cp2);

printf(“cp1=%s\ncp2=%s\n”,cp1,cp2);

}

該程序經(jīng)以前的某些C編譯器編譯后,運(yùn)行結(jié)果為:

cp1=abcdefghij

cp2=ghij

試分析為什么cp2被修改2023/7/3144編譯原理,陳意云,課后答案46.2(續(xù))C語(yǔ)言中,字符串會(huì)添加‘\0’作為串的結(jié)束符,因此,串”12345”存儲(chǔ)為”12345\0”,而串”12345\0abc\0”打印出來(lái)的只有12345常量區(qū)連續(xù)分配因而本題中”12345”和”abcdefghij”存儲(chǔ)為

12345\0abcdefghij\0

cp1cp2

拷貝后結(jié)果為

abcdefghij\0fghij\0

cp1cp2現(xiàn)代編譯器編譯通過(guò),執(zhí)行時(shí)會(huì)出錯(cuò)。(GCC:段錯(cuò)誤/VC非法訪問(wèn))2023/7/3154編譯原理,陳意云,課后答案46.3一個(gè)C程序如下:

typedefstruct_a{

charc1;

longI;

charc2;

doublef;

}a;

typedefstruct_b{

charc1;

charc2;

longl;

doublef;

}b;

main(){

printf(“Sizeofdouble,long,char=%d,%d,%d\n”,sizeof(double),sizeof(long),sizeof(char));

printf(“Sizeofa,b=%d,%d\n”,sizeof(a),sizeof(b));

}

該程序在SPARC/Solaris工作站上運(yùn)行結(jié)果如下:

Sizeofdouble,long,char=8,4,1

Sizeofa,b=24,16

試分析為什么2023/7/3164編譯原理,陳意云,課后答案46.3(續(xù))數(shù)據(jù)對(duì)齊:為了尋址方便A:

char OXXX

long OOOO

char OXXXXXXX

double OOOOOOOOB:

char O

char OXX

long OOOO

double OOOOOOOO可以用gcc–S命令查看編譯后的匯編碼

VC下可以在debug模式下,菜單欄View->DebugWindows中Dissassenbly查看編譯后的匯編碼GCC:(GNU)3.2.2(RedHatLinux3.2.2-5)結(jié)果為20,162023/7/3174編譯原理,陳意云,課后答案46.3(續(xù))#include<stdio.h>

staticstruct_a{

charc1;

longi;

charc2;

doublef;

}a={'A',1,'B',1.0};VC6下,Debug模式Memory窗口查看

GCC:(GNU)3.2.220030222(RedHatLinux3.2.2-5)|A|1|B|1.0|2023/7/3184編譯原理,陳意云,課后答案46.4下面給出一個(gè)C程序及其在X86/Linux下的編譯結(jié)果,根據(jù)所生成的匯編程序來(lái)解釋程序中4個(gè)變量的存儲(chǔ)分配、作用域、生成期和置初始值方式的區(qū)別

staticlongaa=10;

shortbb=20;

func(){

staticlongcc=30;

shortdd=40;

}

生成的匯編代碼:2023/7/3194編譯原理,陳意云,課后答案46.4(續(xù)).file"static.c“.version“01.01”gcc2_compiled:.data.align4.typeaa,@object.sizeaa,4aa:.long10.globlbb.align2.typebb,@object.sizebb,2bb:.value20.align4 .typecc.2,@object.sizecc.2,4cc.2:.long30.text .align4.globlfunc.typefunc,@functionfunc:pushl%ebpmovl%esp,%ebpsubl$4,%espmovw$40,-2(%ebp).L1:leaveret.Lfe1:.sizefunc,.Lfe1-func.ident"GCC:(GNU)egcs-2.91.6619990314/Linux(egcs-1.1.2release)”2023/7/31104編譯原理,陳意云,課后答案46.4(續(xù)).file"static.c“.version“01.01”gcc2_compiled:.data.align4.typeaa,@object.sizeaa,4aa: --aa分配在靜態(tài)數(shù)據(jù)區(qū),作用域?yàn)楸疚募嫫跒檎麄€(gè)程序

.long10–aa靜態(tài)置初值.globlbb--bb分配在靜態(tài)數(shù)據(jù)區(qū),作用域?yàn)槿?,可以被其他文件引用,生存期為整個(gè)程序

.align2.typebb,@object.sizebb,2bb:.value20–bb靜態(tài)置初值

.align4 .typecc.2,@object.sizecc.2,4cc.2:--cc分配在靜態(tài)數(shù)據(jù)區(qū),作用域?yàn)楸疚募嫫跒檎麄€(gè)程序。源程序中在函數(shù)內(nèi)部,為防止重名,需要重命名為cc.2.long30–cc靜態(tài)置初值

.text .align4.globlfunc.typefunc,@functionfunc:pushl%ebpmovl%esp,%ebpsubl$4,%espmovw$40,-2(%ebp)--dd分配在棧上,生存期為func調(diào)用期,動(dòng)態(tài)置初值.L1:leaveret.Lfe1:.sizefunc,.Lfe1-func.ident"GCC:(GNU)egcs-2.91.6619990314/Linux(egcs-1.1.2release)”2023/7/31114編譯原理,陳意云,課后答案46.5假定使用:(a)值調(diào)用;(b)引用調(diào)用;(c)值-結(jié)果調(diào)用;(d)換名調(diào)用。下面程序的結(jié)果分別是什么?

programmain(input,output);

vara,b:integer;

procedurep(x,y,z:integer);

begin

y:=y+1;

z:=z+x;

end;

begin

a:=2;

b:=3;

p(a+b,a,a);

printa;

end.2023/7/31124編譯原理,陳意云,課后答案46.5(續(xù))值調(diào)用

x:=5;y:=2;z:=2;

y:=y+1;z:=z+x; 對(duì)形參的調(diào)用不改變實(shí)參的值,結(jié)果a為2引用調(diào)用

t:=a+b;

a=a+1;

a=a+t; 結(jié)果a為8值-結(jié)果調(diào)用

t:=a+b;

x:=t;y:=a;z:=a

y:=y+1;z:=z+x;

t:=x;a:=y;a:=z; 結(jié)果為7換名調(diào)用

a:=a+1;

a:=a+(a+b); 結(jié)果為92023/7/31134編譯原理,陳意云,課后答案46.6一個(gè)C程序如下:

func(i1,i2,i3)

longi1,i2,i3;

{

longj1,j2,j3;

printf(“Addressofi1i2i3=%o,%o,%o\n”,&i1,&i2,&i3);

printf(“Addressofj1j2j3=%o,%o,%o\n”,&j1,&j2,&j3);

}

main(){

longi1,i2,i3;

func(i1,i2,i3);

}

該程序在X86/Linux上運(yùn)行結(jié)果為:

Addressofi1,i2,i3=27777775460,27777775464,27777775470

Addressofj1,j2,j3=27777775444,27777775440,27777775434

從結(jié)果看func的3個(gè)形參地址逐漸升高,而3個(gè)局部變量地址逐漸降低。試說(shuō)明為什么2023/7/31144編譯原理,陳意云,課后答案46.6(續(xù))C語(yǔ)言中,實(shí)參從右向左進(jìn)棧,所以func(i1,i2,i3)按i3,i2,i1的順序進(jìn)棧而j1,j2,j3按聲明的順序分配2023/7/31154編譯原理,陳意云,課后答案46.7下面的C程序中,printf的調(diào)用僅含格式控制串,運(yùn)行時(shí)輸出3個(gè)參數(shù),分析之

main(){

printf(“%d%d%d\n”);

}2023/7/31164編譯原理,陳意云,課后答案46.7(續(xù))C語(yǔ)言不做實(shí)參和形參個(gè)數(shù)類型是否一致的檢查printf函數(shù)根據(jù)第一個(gè)參數(shù)—格式控制列表,到棧中取參數(shù)本題中雖然只傳了格式控制列表,但是printf函數(shù)分析格式控制列表,認(rèn)為程序員還傳了3個(gè)整型數(shù),因此繼續(xù)去棧中取3個(gè)參數(shù),并輸出之。所以得到了三個(gè)不可預(yù)知值得整數(shù)。2023/7/31174編譯原理,陳意云,課后答案46.8下面給出一個(gè)C程序及其在X86/Linux下的編譯結(jié)果。從結(jié)果看,func的四個(gè)局部變量i1,j1,f1,e1的地址間隔和他們的類型一致,而形參i,j,f,e的地址間隔和他們的類型不一致,試分析原因

func(i,j,f,e)

shorti,j;floatf,e;

{

shorti1,j1;floatf1,e1;

printf(“Addressofi,j,f,e=%o,%o,%o,%o\n”,&i,&j,&f,&e);

printf(“Addressofi1,j1,f1,e1=%o,%o,%o,%o\n”,&i1,&j1,&f1,&e1);

printf(“Addressofshort,int,long,float,double=%d,%d,%d,%d,%d\n”,sizeof(short),sizeof(int),sizeof(long),sizeof(float),sizeof(double));

}

main(){

shorti,j;floatf,e;

func(i,j,f,e);

}

運(yùn)行結(jié)果:

Addressofi,j,f,e=35777772536,35777772542,35777772544,35777772554

Addressofi1,j1,f1,e1=35777772426,35777772426,35777772424,35777772420,35777772414

Sizeofshort,int,long,float,double=2,4,4,4,82023/7/31184編譯原理,陳意云,課后答案46.8(續(xù))C語(yǔ)言為了不保證實(shí)參和形參類型一致,因此為了盡可能保證得到正確結(jié)果,編譯器在整型和實(shí)型做實(shí)參時(shí),將他們提升為long和double傳遞。但是函數(shù)內(nèi)部取參數(shù)時(shí),仍按照原來(lái)的類型去取2023/7/31194編譯原理,陳意云,課后答案46.8(續(xù))main傳參數(shù)時(shí),提升數(shù)據(jù)類型func取參數(shù)時(shí),按原來(lái)的數(shù)據(jù)類型i:short->int4字節(jié)j:short->int4字節(jié)f:long->double8字節(jié)e:long->double8字節(jié)i:short2字節(jié)j:short2字節(jié)f:long4字節(jié)e:long4字節(jié)2023/7/31204編譯原理,陳意云,課后答案46.9一個(gè)C程序

func(c,l)

charc;longl;

{

func(c,l);

}

在x86/Linux上編譯生成的匯編代碼如下,請(qǐng)說(shuō)明char和long在參數(shù)傳遞和存儲(chǔ)分配上的區(qū)別2023/7/31214編譯原理,陳意云,課后答案46.9(續(xù)).file"parameter.c“.version“01.01”gcc2_compiled.:.text.align4.globlfunc.typefunc,@functionfunc:pushl%ebp--將老的基址指針壓棧

movl%esp,%ebp--將當(dāng)前棧頂指針作為基址

subl$4,%esp--分配空間

movl8(%ebp),%eaxmovb%al,-1(%ebp)movl12(%ebp),%eaxpushl%eaxmovsbl-1(%ebp),%eax

pushl%eaxcallfuncaddl$8,%esp.L1:leaveret.Lfe1:.sizefunc,.Lfe1-func.ident"GCC:(GNU)egcs-2.91.6619990314/Linux(egcs-1.1.2release)”2023/7/31224編譯原理,陳意云,課后答案46.9(續(xù))SomeAT&TASMSyntax寄存器:

8個(gè)32-bit寄存器%eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp;操作符源目的-1(%ebp):基址:%ebp,偏移:-1加在指令后的符號(hào)表示操作數(shù)的長(zhǎng)度:

b(byte,8-bit)

w(word,16-bits)

l(long,32-bits)movsbl:

movs:符號(hào)擴(kuò)展指令

movsbl意味著movs(from)byte(to)long;movbw意味著movs(from)byte(to)word;movswl意味著movs(from)word(to)long。More:plzgoogle“AT&T

ASM”2023/7/31234編譯原理,陳意云,課后答案46.9(續(xù))movl8(%ebp),%eax --取cmovb%al,-1(%ebp) --取其字節(jié)值,存入分配的存儲(chǔ)單元movl12(%ebp),%eax--取lpushl%eax --l壓棧movsbl-1(%ebp),%eax--取c,并轉(zhuǎn)換成longpushl%eax --c壓棧callfunc --調(diào)用funcaddl$8,%esp --恢復(fù)壓棧前狀態(tài)2023/7/31244編譯原理,陳意云,課后答案46.10從例6.5可以看到,C程序執(zhí)行時(shí)只用到了控制鏈,不需要使用訪問(wèn)鏈.為什么Parscal程序執(zhí)行時(shí)需要使用訪問(wèn)鏈,而C程序不需要?2023/7/31254編譯原理,陳意云,課后答案46.10(續(xù))PASCAL允許過(guò)程嵌套,執(zhí)行時(shí),可以訪問(wèn)非全局且非局部的變量,所以需要訪問(wèn)鏈幫助確定數(shù)據(jù)所在活動(dòng)記錄在棧中的位置

而C不允許過(guò)程嵌套,只能訪問(wèn)全局和局部變量,所以不需要訪問(wèn)鏈。2023/7/31264編譯原理,陳意云,課后答案46.11下面是求階乘的Pascal程序.畫(huà)出程序第三次進(jìn)入函數(shù)factor時(shí)的活動(dòng)記錄棧和靜態(tài)鏈.

programfact(input,output);

varf,n:integer;

functionfactor(n:integer):integer;

begin

ifn=0thenfactor:=1

elsefactor:=n*(factor(n-1))

end;

beginn:=5;f:=factor(n);write(f)

end.2023/7/31274編譯原理,陳意云,課后答案46.11(續(xù))factf,nfactor訪問(wèn)鏈nfactor訪問(wèn)鏈nfactor訪問(wèn)鏈n1222023/7/31284編譯原理,陳意云,課后答案46.12在下面假想的程序中,第(11)行語(yǔ)句f:=a調(diào)用函數(shù)a,a傳遞函數(shù)addm作為返回值.

(a)畫(huà)出該程序執(zhí)行的活動(dòng)樹(shù).

(b)假定非局部名字使用靜態(tài)作用域,為什么該程序在棧式分配情況下不能正確工作?

(c)在堆分配策略下,該程序的輸出是什么?2023/7/31294編譯原理,陳意云,課后答案46.12(續(xù))programret(input,output); varf:function(integer):integer; functiona:function(integer):integervarm:integer;functionaddm(n:integer):integerbeginreturnm+nend;beginm:=0;returnaddmend;procedureb(g:function(integer):integer);beginwriteln(g(2))end;beginf:=a;b(f)end2023/7/31304編譯原理,陳意云,課后答案46.12(續(xù))活動(dòng)樹(shù)如右圖在執(zhí)行addm時(shí),只有ret,b和addm的活動(dòng)記錄,a的已釋放。如果是靜態(tài)作用域,n對(duì)應(yīng)的是第(4)行中的m,他處于a的活動(dòng)記錄中,而此時(shí)a的已釋放。堆分配結(jié)果是2retabaddm2023/7/31314編譯原理,陳意云,課后答案46.13為什么C語(yǔ)言允許函數(shù)類型(的指針)作為函數(shù)的返回值類型,而Pascal語(yǔ)言卻不允許?2023/7/31324編譯原理,陳意云,課后答案46.13(續(xù))參考6.12課本P2022023/7/31334編譯原理,陳意云,課后答案46.14一個(gè)C語(yǔ)言程序如下:

intn;

intf(intg){

intm;

m=n;

if(m==0) return1;

else{

n=n-1;returnm*f(n);

}

}

main(){

n=5;printf(“%dfactorialis%d\n”,n,f(n));

}

該程序的運(yùn)行結(jié)果不是我們所期望的

5factorialis120

而是

0factorialis120

試說(shuō)明原因.2023/7/31344編譯原理,陳意云,課后答案46.14(續(xù))參數(shù)逆序進(jìn)棧,因此,f(n)先被執(zhí)行,而f(n)執(zhí)行結(jié)束時(shí),n值已經(jīng)被改寫(xiě)為0,此時(shí)再將n值壓棧,因而輸出“0factorialis120”2023/7/31354編譯原理,陳意云,課后答案46.15下面程序在SPARC/SUN工作站上運(yùn)行時(shí)陷入死循環(huán),試說(shuō)明原因.如果將第7行的long*p改成short*p,并且將第22行l(wèi)ongk改成shortk后,loop中的循環(huán)體執(zhí)行一次便停止了.試說(shuō)明原因.

main(){

addr();

loop();

}

long*p;

loop(){

longi,j;

j=0;

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

(*p)--;

j++;

}

}

addr(){

longk;

k=0;

p=&k;

}2023/7/31364編譯原理,陳意云,課后答案46.15(續(xù))程序運(yùn)行時(shí)陷入死循環(huán)的原因是由于p指向分配給i的存儲(chǔ)單元引起的。循環(huán)體執(zhí)行一次便停止時(shí)由于p指向分配給i的高位字節(jié)引起的。C語(yǔ)言的實(shí)現(xiàn)是采用棧式分配,使得函數(shù)addr和函數(shù)loop的活動(dòng)記錄先后從同樣的存儲(chǔ)單元開(kāi)始分配,從而長(zhǎng)整數(shù)k和i先后分配在同樣的存儲(chǔ)單元,因此p指向分配給i的存儲(chǔ)單元。SPARC/SUN工作站上整數(shù)的存放方式是低地址放高位字節(jié),而高地址放低位字節(jié)。另外,活動(dòng)記錄棧是從高地址向低地址方向增長(zhǎng)。當(dāng)k改為短整型且p改為短整型指針后,那么p指向由i的兩個(gè)低位字節(jié)組成的短整數(shù)。執(zhí)行(*p)--使得這兩個(gè)字節(jié)構(gòu)成的短整數(shù)等于-1。而從整個(gè)4個(gè)字節(jié)看時(shí),是65535,遠(yuǎn)大于10。所以循環(huán)體執(zhí)行一次便停止。2023/7/31374編譯原理,陳意云,課后答案46.16一個(gè)C語(yǔ)言程序

main()

{

func();

printf(“Returnfromfunc\n”);

}

func()

{

chars[4];

strcpy(s,”12345678”);

printf(“%s\n”,s);

}

在X86/Linux操作系統(tǒng)上的運(yùn)行結(jié)果如下:

12345678

Returnfromfunc

Segmentationfault(coredumped)

試分析為什么會(huì)出現(xiàn)這樣的運(yùn)行錯(cuò)誤.2023/7/31384編譯原理,陳意云,課后答案46.16(續(xù))數(shù)組越界訪問(wèn)。出現(xiàn)短錯(cuò)誤,說(shuō)明控制鏈被破壞func可以返回main說(shuō)明func的返回地址沒(méi)有被破壞,而main不能返回,說(shuō)明main的返回地址被破壞本題RedHatLinux3.2.

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論