资源预览内容
第1页 / 共43页
第2页 / 共43页
第3页 / 共43页
第4页 / 共43页
第5页 / 共43页
第6页 / 共43页
第7页 / 共43页
第8页 / 共43页
第9页 / 共43页
第10页 / 共43页
亲,该文档总共43页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
编译原理习题课(4),栾 俊 15.08.2020,15.08.2020,.,2,6.1,使用Pascal的作用域规则,确定下面程序中用于名字a,b的每个出现的声明。程序输出整数1,2,3,4 program a (input output); procedure b (u, v, x, y : integer); var a : record a, b : integer end; b : record b, a : integer end; begin with a do begin a := u; b := v end; with b do begin a := x; b := y end; writeln (a.a, a.b, b.a, b.b) end; begin b(1, 2, 3, 4) end.,15.08.2020,.,3,6.1 (续),with aarecorda:=uaa.ab:=vba.bwith bbrecorda:=xab.ab:=ybb.b,15.08.2020,.,4,6.2,考虑下面的C程序 main() char * cp1, * cp2; cp1 = “12345”; cp2 = “abcdefghij”; strcpy(cp1, cp2); printf(“cp1 = %s n cp2 = %s n”, cp1, cp2); 该程序经以前的某些C编译器编译后,运行结果为: cp1 = abcdefghij cp2 = ghij 试分析为什么cp2被修改,15.08.2020,.,5,6.2 (续),C语言中,字符串会添加0作为串的结束符,因此,串”12345”存储为”123450”,而串”123450abc0”打印出来的只有12345 常量区连续分配 因而本题中”12345”和”abcdefghij”存储为1 2 3 4 5 0 a b c d e f g h i j 0cp1 cp2拷贝后结果为a b c d e f g h i j 0 f g h i j 0cp1 cp2 现代编译器编译通过,执行时会出错。(GCC: 段错误 / VC 非法访问),15.08.2020,.,6,6.3,一个C程序如下:typedef struct _a char c1; long I; char c2; double f; a; typedef struct _b char c1; char c2; long l; double f; b;main() printf(“Size of double, long, char = %d,%d,%dn”, sizeof(double), sizeof(long), sizeof(char); printf(“Size of a, b = %d,%dn”, sizeof(a), sizeof(b);该程序在SPARC/Solaris工作站上运行结果如下:Size of double, long, char = 8,4,1Size of a, b = 24,16试分析为什么,15.08.2020,.,7,6.3 (续),数据对齐:为了寻址方便 A:charOXXXlongOOOOcharOXXX XXXXdoubleOOOO OOOO B:charOcharOXXlongOOOO doubleOOOO OOOO 可以用gcc S命令查看编译后的汇编码VC下可以在debug模式下,菜单栏View-Debug Windows中 Dissassenbly查看编译后的汇编码 GCC: (GNU) 3.2.2 (Red Hat Linux 3.2.2-5)结果为20,16,15.08.2020,.,8,6.3 (续),#include static struct _achar c1;long i;char c2;double f; a = A, 1, B, 1.0; VC6下,Debug模式Memory窗口查看,GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5),|A |1 |B |1.0 |,15.08.2020,.,9,6.4,下面给出一个C程序及其在X86/Linux下的编译结果,根据所生成的汇编程序来解释程序中4个变量的存储分配、作用域、生成期和置初始值方式的区别static long aa = 10;short bb = 20;func() static long cc = 30; short dd = 40;生成的汇编代码:,15.08.2020,.,10,6.4 (续),.file static.c“ .version “01.01” gcc2_compiled: .data .align 4 .type aa,object .size aa,4 aa: .long 10 .globl bb .align 2 .type bb,object .size bb,2 bb: .value 20 .align 4 .type cc.2,object .size cc.2,4,cc.2: .long 30 .text .align 4 .globl func .type func,function func: pushl %ebp movl %esp, %ebp subl $4, %esp movw $40, -2(%ebp) .L1: leave ret .Lfe1: .size func,.Lfe1-func .ident GCC: (GNU) egcs-2.91.66 19990314/Linux(egcs-1.1.2 release)”,15.08.2020,.,11,6.4 (续),.file static.c“ .version “01.01” gcc2_compiled: .data .align 4 .type aa,object .size aa,4 aa: -aa分配在静态数据区,作用域为本文件,生存期为整个程序 .long 10 aa静态置初值 .globl bb -bb分配在静态数据区,作用域为全局,可以被其他文件引用,生存期为整个程序 .align 2 .type bb,object .size bb,2 bb: .value 20 bb静态置初值 .align 4 .type cc.2,object .size cc.2,4,cc.2: -cc分配在静态数据区,作用域为本文件,生存期为整个程序。源程序中在函数内部,为防止重名,需要重命名为cc.2 .long 30 cc静态置初值 .text .align 4 .globl func .type func,function func: pushl %ebp movl %esp, %ebp subl $4, %esp movw $40, -2(%ebp) -dd分配在栈上,生存期为func调用期,动态置初值 .L1: leave ret .Lfe1: .size func,.Lfe1-func .ident GCC: (GNU) egcs-2.91.66 19990314/Linux(egcs-1.1.2 release)”,15.08.2020,.,12,6.5,假定使用:(a)值调用;(b)引用调用;(c)值-结果调用;(d)换名调用。下面程序的结果分别是什么?program main(input, output); var a, b : integer; procedure p(x, y, z : integer); begin y := y + 1; z := z + x; end; begin a := 2; b := 3; p(a + b, a, a); print a; end.,15.08.2020,.,13,6.5 (续),值调用x := 5; y := 2; z := 2;y := y + 1; z := z + x;对形参的调用不改变实参的值,结果a为2 引用调用t := a + b; a = a + 1;a = a + t;结果a为8 值-结果调用t:=a+b;x:=t;y:=a;z:=ay:=y+1;z:=z+x;t:=x;a:=y;a:=z;结果为7 换名调用a := a+1;a := a+(a+b);结果为9,15.08.2020,.,14,6.6,一个C程序如下:func(i1, i2, i3)long i1, i2, i3; long j1, j2, j3; printf(“Address of i1 i2 i3 = %o,%o,%on”, 该程序在X86/Linux上运行结果为:Address of i1, i2, i3 = 27777775460,27777775464,27777775470Address of j1, j2, j3 = 27777775444,27777775440,27777775434从结果看func的3个形参地址逐渐升高,而3个局部变量地址逐渐降低。试说明为什么,15.08.2020,.,15,6.6 (续),C语言中,实参从右向左进栈,所以func(i1, i2, i3)按i3,i2,i1的顺序进栈 而j1,j2,j3按声明的顺序分配,15.08.2020,.,16,6.7,下面的C程序中,printf的调用仅含格式控制串,运行时输出3个参数,分析之main() printf(“%d %d %dn”);,15.08.2020,.,17,6.7 (续),C语言不做实参和形参个数类型是否一致的检查 printf函数根据第一个参数格式控制列表,到栈中取参数 本题中虽然只传了格式控制列表,但是printf函数分析格式控制列表,认为程序员还传了3个整型数,因此继续去栈中取3个参数,并输出之。 所以得到了三个不可预知值得整数。,15.08.2020,.,18,6.8,下面给出一个C程序及其在X86/Linux下的编译结果。从结果看,func的四个局部变量i1,j1,f1,e1的地址间隔和他们的类型一致,而形参i,j,f,e的地址间隔和他们的类型不一致,试分析原因func(i, j, f, e)short i, j; float f, e; short i1, j1; float f1, e1; printf(“Address of i, j, f,e = %o,%o,%o,%on”, 运行结果:Address of i,j,f,e = 35777772536, 35777772542, 35777772544,35777772554Address of i1,j1,f1,e1 = 35777772426, 35777772426, 35777772424, 35777772420, 35777772414Size of short,int,long,float,double = 2,4,4,4,8,15.08.2020,.,19,6.8 (续),C语言为了不保证实参和形参类型一致,因此为了尽可能保证得到正确结果,编译器在整型和实型做实参时,将他们提升为long和double传递。 但是函数内部取参数时,仍按照原来的类型去取,15.08.2020,.,20,6.8 (续),15.08.2020,.,21,6.9,一个C程序func(c, l)char c; long l; func(c, l);在x86/Linux上编译生成的汇编代码如下,请说明char和long在参数传递和存储分配上的区别,15.08.2020,.,22,6.9 (续),.file pa
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号