当前位置:文档之家› 4编译原理,陈意云 ,课后答案4(方案).ppt

4编译原理,陈意云 ,课后答案4(方案).ppt

.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
19990314/Linux(egcs-1.1.2 release)”
..........
10
6.4 (续)
.file "static.c“
.version “01.01”
gcc2_compiled:
.data
.align 4
.type aa,@object
.size aa,4
aa:
--aa分配在静态数据区,作
• 常量区连续分配
• 因而本题中”12345”和”abcdefghij”存储为 1 2 3 4 5 \0 a b c d e f g h i j \0
cp1
cp2
拷贝后结果为
a b c d e f g h i j \0 f g h i j \0
cp1
cp2
• 现代编译器编译通过,执行时会出错。(GCC: 段错误 / VC 非法访问)
..........
12
6.5 (续)
• 值调用 x := 5; y := 2; z := 2; y := y + 1; z := z + x; 为2
• 引用调用 t := a + b; a = a + 1; a = a + t;
• 值-结果调用 t:=a+b; x:=t;y:=a;z:=a y:=y+1;z:=z+x; t:=x;a:=y;a:=z;
..........
11
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.
• VC6下,Debug模式Memory窗口查看
|A
|1
|B
|1.0
|
• GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
..........
8
6.4
• 下面给出一个C程序及其在X86/Linux下的编译结 果,根据所生成的汇编程序来解释程序中4个变量 的存储分配、作用域、生成期和置初始值方式的 区别
short i1, j1; float f1, e1; printf(“Address of i, j, f,e = %o,%o,%o,%o\n”, &i, &j, &f, &e); printf(“Address of i1,j1,f1,e1 = %o,%o,%o,%o\n”, &i1, &j1, &f1, &e1); printf(“Address of short,int,long,float,double = %d,%d,%d,%d,%d\n”, sizeof(short), sizeof(int), sizeof(long), sizeof(float), sizeof(double)); } main(){ short i, j; float f, e; func(i, j, f, e); } 运行结果:
..........
5
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,%d\n”, sizeof(double), sizeof(long), sizeof(char)); printf(“Size of a, b = %d,%d\n”, sizeof(a), sizeof(b)); } 该程序在SPARC/Solaris工作站上运行结果如下: Size of double, long, char = 8,4,1 Size of a, b = 24,16 试分析为什么
• 换名调用 a := a+1; a := a+(a+b);
对形参的调用不改变实参的值,结果a
结果a为8
结果为7 结果为9
..........
13
6.6
• 一个C程序如下: func(i1, i2, i3) long i1, i2, i3; { long j1, j2, j3; printf(“Address of i1 i2 i3 = %o,%o,%o\n”, &i1, &i2, &i3); printf(“Address of j1 j2 j3 = %o,%o,%o\n”, &j1, &j2, &j3); } main(){ long i1, i2, i3; func(i1, i2, i3); } 该程序在X86/Linux上运行结果为: Address of i1, i2, i3 = 27777775460,27777775464,27777775470 Address of j1, j2, j3 = 27777775444,27777775440,27777775434 从结果看func的3个形参地址逐渐升高,而3个局部变量地址逐渐降低。 试说明为什么
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
• GCC: (GNU) 3.2.2 (Red Hat Linux 3.2.2-5)结果为20,16
..........
7
6.3 (续)
• #include <stdio.h> static struct _a{ char c1; long i; char c2; double f; } a = {'A', 1, 'B', 1.0};
..........
6
6.3 (续)
• 数据对齐:为了寻址方便
• A: char long char
OXXX OOOO OXXX XXXX
double
OOOO OOOO
• B: char char long double
O OXX OOOO OOOO OOOO
• 可以用gcc –S命令查看编译后的汇 编码 VC下可以在debug模式下,菜单栏 View->Debug Windows中 Dissassenbly查看编译后的汇编码
..........
17
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; {
.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)”
..........
16
6.7 (续)
• C语言不做实参和形参个数类型是否一致的 检查
• printf函数根据第一个参数—格式控制列表, 到栈中取参数
• 本题中虽然只传了格式控制列表,但是 printf函数分析格式控制列表,认为程序员 还传了3个整型数,因此继续去栈中取3个 参数,并输出之。
• 所以得到了三个不可预知值得整数。
static long aa = 10;
short bb = 20;
func(){
static long cc = 30;
short dd = 40;
} 生成的汇编代码:
..........
9
6.4 (续)
.file "static.c“ .version “01.01” gcc2_compiled:
用域为本文件,生存期为整个程序
.long 10 –aa静态置初值
.globl bb
--bb分配在静态数据区,作
用域为全局,可以被其他文件引用,
相关主题