《计算机系统》——C语言(一)

从今天开始,我们进入高级语言层(第六层)——C语言的学习。程序输入、处理信息并输出结果。本章节展示了一个C怎样输入、处理和输出数值。本章讲述HOL6层的编程。

2.1 变量

计算机能够直接执行指令架构层上的机器语言。因此HOL6层的语句必须先被翻译到ISA3层,然后才能执行或者先到第五层汇编层,再从第五层翻译到第三层。

2.1.1 C编译器

运行程序可以分为三个步骤:

  • 在文本编辑器中用C语言写程序,这个版本叫做源程序。

  • 调用编译器把源程序从C翻译或编译为机器语言,机器语言的目标程序叫做目标程序。

  • 执行目标程序。

*HOL6层的程序在执行前都必须进行翻译。

在写源程序的时候,它像其他文本文档一样保存在磁盘文件中。编译器将生成另一个被称为代码文件的目标程序文件。编译后目标程序在你的文件目录中是否可见取决于你的编译器。

如果想执行一个之前编译过的程序,就不需要再翻译它,而是只需要直接执行它的目标程序即可。如果删掉了磁盘上的目标程序,总是可以通过编译程序来恢复它。但是翻译只能从高层到低层,如果删除了源程序,就不能从目标程序恢复它。

源程序➡

编译器➡

目标程序


2.1.2 机器无关性

ISA3层语言是与机器相关的。假设有两个品牌的计算机X、Y,在ISA3层语言写的用于在X品牌计算机上执行的程序,是不能在Y品牌计算机上运行的。

HOL6层语言一个重要的性质就是它们与机器无关。

假设用C写一个做统计分析的应用程序,想把它卖给X品牌计算机的人,也想把它卖给Y品牌计算机的人,只有当这个统计程序是机器语言格式时才能执行,因为机器语言是与机器相关的。如果这样的话,那么只需在一台机器上调用X品牌的编译器生成X品牌机器语言版本,在另一台机器上调用Y品牌的编译器生成Y品牌机器语言版本,而我们只需要写一个C程序就足够了。


2.1.3 C的内存模型

C编程语言有三种不同种类的变量:全局变量、局部变量和动态分配变量。变量的值存储在计算机的主存中,存储的位置取决于变量的类型。

  • 全局变量存放在内存中的固定位置。

  • 局部变量和参数存放在运行时栈上。

  • 动态分配变量存放在堆上。

全局变量声明在所有函数的外面,且执行过程中位置保持不变。局部变量在函数中声明,函数被调用时它们出现,函数结束时,它们消失。动态分配变量随着malloc()函数的执行出现,随着free()函数的执行消失。

栈是一个值的容器,通过push和pop操作存入值,通过pop操作取出值。存入栈的原则是后进先出。有时候栈也被叫做LIFO表,LIFO是"Last in ,First out"首字母的缩写。

按照如下的顺序对时栈的空间进行分配:

  • 压入返回值的存储空间

  • 压入实参

  • 压入返回地址

  • 压入局部变量的存储空间

当函数结束时,按照相反的顺序释放运行时栈的存储空间;


2.1.4 全局变量和幅值语句

每个C变量都具有三个属性:名字、类型、值

下面这段程序没有实际意义,唯一的目的就是说明这一点。

//Stan Warford
//A nonsense program to illustrate globla variables

#include<stdio.h>
char ch;
int  j;
int main(){
scanf("%c %d",&ch,&j);
j+=5;
ch++;
printf("%c\%n%d\n",ch,j);
return 0;
}

//输入  M 419
//输出  N 424
http://t.csdn.cn/2Em9Q

这篇文章中,该作者介绍了C语言程序语法。

在输出函数printf("%c\%n%d\n",ch,j)中,“%c %d \n"其中的%d仍然是占位符,分别对应后面的参数ch和j。

谨记,当一个函数被调用时,运行时栈上分配了四项:返回值、参数、返回地址和局部变量,由于这段程序的主函数没有参数和局部变量,所在运行时栈上仅分配了标记为retVal的返回值和标记为retAddr的返回地址存储空间。图中显示的返回值是ra0,这是程序结束时操作系统将执行的指令的地址,对于HOL6层的我们来说,OS4层操作系统的细节是隐藏的。


2.1.5 局部变量

全局变量在主存固定的位置进行分配,而局部变量则是在运行时栈上进行分配。在C程序中,局部变量是在主程序内部声明。

下面这段程序声明了一个常量、三个局部变量。

#include <stdio.h>
int main(){
const int bonus=10;
int exam1;
int exam2;
int score;
scanf("%d %d",&exam1,&exam2);
score=(exam1+exam2)/2+bonus;
printf("score=%d/n",score);
return 0;
}

输入68 84
输出score=86

在第一个变量前面的常量bonus.与变量一样,常量有名字、类型和值。不过,与变量不同的是,常量的值不会改变。初始化运算符=将这个常量的值指定为10。

第一条可执行语句是,是把输入流的值赋给exam1和exam2,第二条可执行语句是把输入的两个数值相加得到的和除以2获得平均值,再加上奖励分,接着把数值赋值给score。因为两个输入数值和2都是整数,所以除法运算符/代表整数除法。如果两个变量被声明是浮点型,或者除数写作2.0而不是2,那么除法运算符就代表浮点数除法。整数除法会被截掉余数,而浮点数除法会保留小数部分。要输出浮点变量的值,需要格式字符串中使用%f转换符。


如果把score声明为双精度浮点型,如下所示:

double score;

并且通过2改为2.0把除法强制为浮点数除法,如下所示:

score=(exam1+exam2)/2.0+bonus;

那么输入68和85时,输出是

score=86.5

表达式

15%3

0

14%3

2

13%3

1

12%

0

11%30

2

表达式

15/3

5

14/3

4

13/3

4

12/3

4

11/3

3

两张图展示了一些整型除法和模运算的一些例子。

score

score

exam2

exam2

84

exam1

exam1

64

retAddr

ra0

retAddr

ra0

retVal

retVal

a)输入语句执行前

b)输入语句执行后

两张图所示的是程序中的局部变量的内存模型。

计算机在运行时栈上给所有的局部变量分配存储空间。当main()执行时,返回值、返回地址、局部变量被push入栈中。因为bonus不是变量,所以它不会入栈。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值