程序是怎么跑起来的

什么是程序

程序是指令和数据的集合体,例如c语言的printf(“hello world”),printf是指令,hello world是数据。cpu能够理解的只有机器语言,所以高级语言的程序最后都会编译成机器语言,并且在硬盘或者磁盘中的程序只有被复制到内存中才能执行。内存中保存指令和数据的区域,通过地址来标识。
流程为:程序员用高级语言写程序->将程序编译成机器语言的EXE文件->程序运行时,内存中生成EXE的副本->cpu解释并执行程序内容

cpu是寄存器的集合体

程序是把寄存器为对象来描述的,机器语言主要通过寄存器来处理计数和存储(mov和add等)。

条件分支和循环机制

操作系统把程序从硬盘复制到内存后,假设某段代码的开始地址是0100,cpu每执行一条指令,程序计数器的值就会自动加1,cpu的控制器会参照程序计数器的数值,从内存中读取命令并执行(读取0101的指令)。也就是说,程序计数器决定着程序的流程。
所以条件分支是根据条件执行任意地址的指令(通过指令中的jump操作),循环是重复执行某个地址的指令。
我们会经常在条件分支中使用比较符号,而在cpu中,直接对两个操作数进行减法运算。

函数的调用机制

和循环以及条件分支不同,单纯的跳转无法完成在执行一系列指令后回到函数调用点。
机器语言的call和return可以解决这个问题,函数调用使用的是call指令,这个指令会把调用函数后要执行的指令保存在主存的栈中,指令结束后,再通过函数的出口来执行return命令。return命令是把在栈中存储的地址设定到程序计数器中
也就是说,栈中存储的内容为函数指令 + 返回目的地地址。

字节

二进制的位数一般是8位、16位、32位,8位二进制数为一个字节(bite),字节是最小的信息存储单位。

移位运算和乘除方法

移位运算的是二进制数值的各数位进行左右移位(shift=移位)的运算。移位有左移(向高位方向)和右移(向低位方向)两种。左移后空出来的低位,要进行补0操作。移位运算可以相当于乘法和除法。

便于计算处理的补数

二进制数中表示负数,一般会把最高位作为符号来使用。(负数为1,正数为0)那么-1用8位数来表示是什么呢,可能很多人会以为是10000001,但正确答案是11111111。计算机在做减法运算的时候,其实是在内部做加法运算。表示负数的时候通过将正数取反,再加1就得到负数表示。也就是在1 - 1的时候,10000001 + 11111111 = 00000000,溢出的位忽略不记。
所以取反+1和原来的数,相加为0,也就是一个数和补数相加,结果是0。
当我们知道一个负数的表示时,怎么知道它多大呢。假如负数111111110是负x,那么负数111111110的补数为x。求出x就能得出111111110代表什么数。

小数计算

当我们将float的0.1累加100次后,结果不会得到10。这是因为,有的十进制小数,无法转化为二进制数。小数点后4位用二进制数能表示的取值范围为0.0000~0.1111。这只能表示0.5、0.25、0.125、0.0625的位权组合起来的小数。
于是,计算机中会通过浮点数,也就是通过符号、尾数、基数和指数这4部分来表示的小数。因为计算机中使用二进制数,所以基数为2。(m*n的2次方加符号位)
尾数部分使用正则表达式(根据特定格式来表示数据的形式叫做正则表达式)进行规范。例如0.75 = 0.75 * 10的负一次方,对尾数0.75就有所要求,而不是使用7.5或者75。
具体单精度和双精度浮点数这里不做介绍。

内存

计算机是进行数据处理的设备,而程序表示的就是处理顺序和数据结构。根据变量类型的不同,计算机会分配不同的内存大小。
指针是一种变量,存储着数据的内存地址。通过使用指针,就可以对任意地址的数据进行读写。

  char *a;
  short *b;
  long *c;  

假设abc都是100,使用a可以从100开始读写一个字节数据,使用b可以读写2个字节,使用c可以读写3个字节。
数组是多个同样数据类型的数据在内存中连续排列的形式。数组通过索引来读写数组元素,索引和内存地址的变换工作由编译器实现。

栈和队列

如果每次读取数据都要指定地址和索引,程序会比较麻烦,栈和队列分别定义不同的数据出入方式。如果要实现栈和队列,就要以适当的元素来定义一个用来存储数据的数组,以及对该数组进行读写的函数对。栈的原意是干草堆积成山,当我们最后想还原数据的时候,会使用栈。
队列一般是以环状缓冲区的方式来实现的,从数组的起始开始存储数据,在数组的末尾写入数据后,下一个数据就会被写入数组的起始位置。数据的写入和读出也就循环起来。

链表

链表使数组的删除和追加变得容易。通过链表的索引删除数据,只需要改变索引的值,虽然删除的元素在内存中依旧存在,但在逻辑上已经被删除。如果不使用链表数组,在中途删除或者追加元素时,都要移动大量元素。
通过二叉查找树,则可以高效对数据进行检索。二叉树是指在链表基础上往数组中追加元素时,考虑到数据的大小关系,将其分成两个方向的表现形式。如果新添加的数比先前的数大,就放到右边,否则放到左边。使用二叉查找树加快了数组查找的效率,当目标数据大于当前查找的数据时,查找右边,否则查找左边。

存储设备

内存利用电流来实现存储,而磁盘通过磁效应来存储。程序保存在存储设备中,通过有序地读取到内存中实现运行。(磁盘的读取速度慢)
磁盘缓存指的是从磁盘中读出的数据存储到内存空间中的方式。把低速设备的数据保存在高速设备中,需要时可以直接从高速设备中读取,这种缓存方式在其他情况下也会用到。
虚拟内存是把磁盘的一部分作为假想的内存来使用,借助虚拟内存,在内存不足的时候也可以运行程序。
为了实现虚拟内存,必须把实际内存的内容,和磁盘上的虚拟内存中的内容进行交换。虚拟内存的使用有分页式和分段式,分页式指的是不考虑程序构造,把程序按照一定大小的页进行分割,并以页为单位在内存和磁盘中进行置换。需要运行的部分page in,不需要的部分page out。
page in和page out往往伴随着低俗的磁盘访问,因此在这个过程中应用的运行会变得卡顿。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值