精华内容
参与话题
问答
  • 书从计算机的内部结构开始讲起,以图配文的形式详细讲解了二进制、内存、数据压缩、源文件和可执行文件、操作系统和应用程序的关系、汇编语言、硬件控制方法等内容,目的是让读者了解从用户双击程序图标到程序开始...
  • 《计算机是怎么跑起来的》--- 矢泽久雄 以图配文,以计算机的三大原则为开端、相继介绍了计算机的结构、手工汇编、程序流程、算法、数据结构、面向对象编程、数据库、TCP/IP 网络、数据加密、XML、计算机系统开发...
  • 1.程序运行必要的硬件 1.必须有一个存储器,记忆程序和数据的存储器。 2.必须有一个控制器,控制程序执行的控制器。 3.必须有一个运算器,完成数据加工处理的运算器。 4.必须有输入设备和输出设备,用于进行...

    首先我们需要知道这些基础的计算机软硬件知识。
    1.程序运行必要的硬件
    1.必须有一个存储器,记忆程序和数据的存储器。
    2.必须有一个控制器,控制程序执行的控制器。
    3.必须有一个运算器,完成数据加工处理的运算器。
    4.必须有输入设备和输出设备,用于进行人机通信。
    2.程序是什么,由什么组成?
    程序是指示计算机每一步动作的计算机指令,由指令(机器语言)和数据组成。
    程序的运行环境=操作系统+硬件。
    3.cpu
    1.寄存器:用来暂时存储指令、和数据。不同的cpu内部有20-几百个寄存器,了解即可。
    A.寄存器的主要种类和功能
    种类 功能
    累加寄存器 存储执行运算的数据和运算后的数据
    标志寄存器 存储运算处理后的CPU的状态
    程序计数器 存储下一条指令所在内存的地址
    基址寄存器 存储数据内存的起始地址
    变址寄存器 存储基址寄存器的相对地址
    通用寄存器 存储任意数据
    指令寄存器 存储指令。CPU内部使用,程序员无法通过程序对该寄存器进行读写操作
    栈寄存器 存储栈区域的起始地址

    B.如图实例(x86系列cpu主要寄存器)
    寄存器名 名称 主要功能
    eax 累加寄存器 同上图
    ebx 基址寄存器 存储内存地址
    ecx 计数寄存器 计算循环次数
    edx 数据计算器 存储数据
    esi 源地址寄存器 存储数据发送源的内存地址
    edi 目标地址寄存器 存储数据发送目标的内存地址
    ebp 扩展基址指针寄存器 存储数据存储领域基点的内存地址
    esp 扩展栈指针寄存器 存储栈中最高位数据的内存地址
    2.控制器:负责把内存上的指令、数据等数据读入寄存器,并根据指令执行的结果来控制计算机。
    3.运算器:负责运算从内存读入到寄存器的数据。
    4.时钟:负责发出cpu开始计时的时钟信号
    4.指令在cpu内部运行示意图
    这里写图片描述
    C.指令在cpu内部运行示意图
    扩展,如图D、机器指令的主要类型及功能
    类型 功能
    数据转送指令 寄存器和内存、内存和内存、寄存器与外围设备之间的读取操作
    运算指令 用累加寄存器执行算术运算、逻辑运算、比较运算以及移位运算
    跳转指令 实现条件分支、循环、强制跳转等
    call/return 指令 函数的调用、返回调用前的地址
    D.机器指令的主要类型及功能
    高级语言编写出来的程序,最后都转变为这些简单的指令了。
    5.内存
    内存的作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。计算机内存主要以下几种:
    a. 高速缓冲存储器(Cache):它位于CPU与内存之间,读写速度比内存更快的存储器。当CPU向内存中写入或读出数据时,这个数据也被存储进高速缓冲存储器中。当CPU再次需要这些数据时,CPU就从高速缓冲存储器读取数据,而不是访问较慢的内存,当然,如需要的数据在Cache中没有,CPU会再去读取内存中的数据。
    b. 只读存储器(ROM):ROM表示只读存储器(Read Only Memory),ROM中的一旦被写入就不能再更改,信息只能读出,即使机器停电,这些数据也不会丢失。ROM一般用于存放计算机的基本程序和数据,如BIOS ROM。
    c. 随机存储器(RAM):随机存储器(Random Access Memory)表示既可以从中读取数据,也可以写入数据。当机器电源关闭时,存于其中的数据就会丢失。也就是我们常说的内存条。
    d. 可以把内存想象成这样。
    内存
    这里写图片描述

    6.磁盘
    磁盘的原理与使用都比较简单,笔者不再详细讲。
    看完基础的计算机软硬件知识,我们来了解编程语言,所以这里以java和C语言为例。有的读者可能要问为什么要以俩个为例。因为俩种语言在执行过程存在差别(虽然现在用编译型、解释型来分类编程语言已经有点力不从心了)。
    计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言编写的程序。
    1. C语言
    C语言是属编译类语言。编译型语言写的程序执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高,但是可移植性差。

    E.C语言编译过程
    这里写图片描述
    2. Java语言
    同C语言一样,java也是将java语法记述的源代码编译后运行。不过,编译后生成的并不是针对特定硬件环境使用的本地代码,而是字节码(也是我们说的.class文件)。运行时由java虚拟机转换成本地代码运行。所以代码的可移植性好,执行效率低。

    F.java语言编译过程
    这里写图片描述
    总结
    一种是程序编译成机器语言,操作系统把机器语言(指令)复制到内存。内存中最有可能被cpu用到的数据放入cache。然后cpu与内存交互处理数据(程序执行)。
    二是java虚拟机解释成机器语言放到内存中,内存中最有可能被cpu用到的数据放入cache。然后cpu与内存交互处理数据(程序执行)。
    这里写图片描述

    展开全文
  • 程序怎么跑起来

    2017-09-20 23:13:36
    程序怎么跑起来的。日本作者。适合小白。多次印书。基础的才是最重要的。不是吗??????记录了来来来
  • 一个程序怎样跑起来的(一)

    千次阅读 2016-10-22 18:33:01
    找工作期间断断续续看了一些关于程序运行原理的东西,这里做个简单的小结。因为这方面还不熟悉,可能有些东西描述的不准确甚至有纰漏,还希望大家能及时指出。 首先看一下从一个我们编写的源代码程序到一个被电脑...

    找工作期间断断续续看了一些关于程序运行原理的东西,这里做个简单的小结。因为这方面还不熟悉,可能有些东西描述的不准确甚至有纰漏,还希望大家能及时指出。

    首先看一下从一个我们编写的源代码程序到一个被电脑运行的程序需要几个步骤:

    这个转换图中可以看出,编译、装载、运行这三个步骤就是本文所描述的核心过程,中间会有部分内容涉及到对程序内容和进程的相关描述。

    本文的源代码以main.c,head.h,func.c三个文件为例进行说明。

    main.c

    #include<stdio.h>
    #include"head.h"
    int main(){
        int a = 12;
        int b = 23;
        int c = add(a, b);
        printf("%d\n",c);
        return 0;
    }

    head.h

    int add(int a, int b);

    fun.c

    int add(int a, int b){
        return (a + b);
    }


    1、编译

    再解释编译的过程之前,首先说明一下为什么要有编译这个过程。现在的计算机在执行的时候,其实只能识别机器语言(二进制形式),除了机器语言以外的东西计算机是完全看不懂的。当我们用高级语言编写好程序后,为了让我们的程序能够正常的被机器识别和执行,需要一个转换的过程来把我们用高级语言编写的程序转换为计算机能看懂的机器语言,这个过程就是编译的过程。理解了为什么需要编译过程,也就明白了编译的作用:编译过程就是把我们编写的源代码转换为机器可以识别的机器语言(二进制形式)
    理解了编译过程的作用,下面来详细看一下编译过程的具体细节。编译的过程可以分解为一下4个步骤:
    • 预处理
    • 编译
    • 汇编
    • 链接 
    针对我这里面的三个文件main.c,head.h,fun.c,整体的编译过程就是这样的:

    下面详细说一下每一步的内容
    1、预处理:
    预处理过程主要处理源代码文件中以“#”开始的预编译指令,比如“#include”,“define”等等。特别说一下“#incldue”指令,它会把被包含的文件插入到该预编译指令的位置,而且这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。在gcc下,利用-E选项可以生成预处理后的文件。于是利用下面两条命令:
    gcc -E main.c -o main.i
    gcc -E fun.c -o fun.i
    生成预处理后的main.i文件和fun.i文件。你如果打开了main.i你会发现,单单是“#include<stdio.h>”一条,就会在main.c中插入几百行代码。
    fun.i:

    2、编译。编译过程是把预处理完的文件进行一系列词法分析、语法分析、语义分析以及优化后产生相应的汇编代码文件。这个过程往往是我们所说的整个程序构建的核心部分。我们可以用下面两条命令
    gcc -S main.i -o main.s
    gcc -S fun.i -o fun.s
    产生编译的结果文件main.s 和 fun.s。这两个文件的内容现在完整的贴在下面,后面讲到运行的时候会更详细的分析他们。
    main.s:
     .file   "main.c"
      2     .section    .rodata
      3 .LC0:
      4     .string "%d\n"
      5     .text
      6     .globl  main
      7     .type   main, @function
      8 main:
      9 .LFB0:
     10     .cfi_startproc
     11     pushl   %ebp
     12     .cfi_def_cfa_offset 8
     13     .cfi_offset 5, -8
     14     movl    %esp, %ebp
     15     .cfi_def_cfa_register 5
     16     andl    $-16, %esp
     17     subl    $32, %esp
     18     movl    $12, 20(%esp)
     19     movl    $23, 24(%esp)
     20     movl    24(%esp), %eax
     21     movl    %eax, 4(%esp)
     22     movl    20(%esp), %eax
     23     movl    %eax, (%esp)
     24     call    add
     25     movl    %eax, 28(%esp)
     26     movl    28(%esp), %eax
     27     movl    %eax, 4(%esp)
     28     movl    $.LC0, (%esp)
     29     call    printf
     30     movl    $0, %eax
     31     leave
     32     .cfi_restore 5
     33     .cfi_def_cfa 4, 4
     34     ret
     35     .cfi_endproc
     36 .LFE0:
     37     .size   main, .-main
     38     .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
     39     .section    .note.GNU-stack,"",@progbits
    
    fun.s:
      1     .file   "fun.c"
      2     .text
      3     .globl  add
      4     .type   add, @function
      5 add:
      6 .LFB0:
      7     .cfi_startproc
      8     pushl   %ebp
      9     .cfi_def_cfa_offset 8
     10     .cfi_offset 5, -8
     11     movl    %esp, %ebp
     12     .cfi_def_cfa_register 5
     13     movl    12(%ebp), %eax
     14     movl    8(%ebp), %edx
     15     addl    %edx, %eax
     16     popl    %ebp
     17     .cfi_restore 5
     18     .cfi_def_cfa 4, 4
     19     ret
     20     .cfi_endproc
     21 .LFE0:
     22     .size   add, .-add
     23     .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
     24     .section    .note.GNU-stack,"",@progbits

    3、汇编。汇编过程就是利用汇编器,将汇编代码转变成机器可执行的指令,每一条汇编语句几乎都对应一条机器指令。我们用下面两条命令
    gcc -c main.s -o main.o
    gcc -c fun.s -o fun.o
    生成包含机器指令的文件。需要注意的是,汇编的结果就是机器指令了,不同于我们前两步可以用不同文本编辑器能够看到内容的普通文件,它们是二进制格式的文件,在Linux下,是一种ELF格式的文件。
    4、链接。链接简单的理解就是将多个目标文件合并生成一个最终的可执行文件。在Linux下,这个最终的可执行文件也是一个ELF格式。命令如下
    gcc main.o fun.o -o res
    这个res就是我们最终生成的可执行文件。



    
    
    展开全文
  • 程序怎样跑起来的(1)

    千次阅读 2018-06-26 10:12:18
    程序怎样跑起来的》笔记 第1章.对程序员来说CPU是什么 1:程序是什么? 指令序列,指示计算机每一步动作的一组指令。 2:程序是由什么组成的? 指令和数据,程序是指令和数据的组合体。 3:什么是机器语言...

    《程序是怎样跑起来的》笔记

    主要参考文章:https://blog.csdn.net/u014222687/article/category/6295175

    第1章.对程序员来说CPU是什么

    1:程序是什么?

    指令序列,指示计算机每一步动作的一组指令。
    

    2:程序是由什么组成的?

    指令和数据,程序是指令和数据的组合体。
    

    3:什么是机器语言?

    CPU可以直接识别和使用的语言,CPU能够直接识别和执行的只有机器语言。
    

    4:正在运行的程序存储在什么位置?

    内存,硬盘等媒介上保存的程序被复制到内存后才能运行。
    

    5:什么是内存地址?

     内存中,用来表示命令和数据存储位置的数值。内存是保存命令和数据的场所,通过地址来标记和指定。地址由整数值表示。
    

    附注:通过地址寻找,地址其实也是抽象概念,找到一个地方,称之为原点或零点,然后寻址就是,从原点开始转过的角度,间隔的距离。

    6:计算机的构成元件中,负责程序的解释和运行的是哪个?

    CPU(中央处理器(Central Processing Unit))。计算机的构成元件中,根据程序的指令来进行数据运算,并控制整个计算机的设备称作CPU。
    

    内存:通常说的内存指的是计算机的主存储器,简称主存。主存通过控制芯片等与CPU相连,主要负责存储指令和数据,主存由可读写的元素构成,每个字节都带有一个地址编码。CPU可以通过地址读取主存中的指令和数据,当然也可以写入数据。

    CPU与内存:CPU是用来计算处理信息的,而信息来自电脑的硬盘。一条信息要经过硬盘,内存,三级缓存,二级缓存,一级缓存才能进入CPU内部,再经过里面的存储单元,最后被CPU处理。以上的路径信息提取速度逐渐增加。内存如果大的话,CPU单位时间内处理的信息量就多。所以内存和CPU之间有一点小关系的。

    程序运行流程:
    这里写图片描述

    CPU的组成:
    这里写图片描述
    运行过程:程序启动后,根据时钟信号,控制器会从内存中读取指令和数据。通过对这些指令加以解释和运行,运算器就会对数据进行运算,控制器根据运算结果来控制计算机,处理的场所在寄存器内。(也就是程序开始时,时钟开始调用时,指令数据存储近寄存器,运算器对寄存器进行运算,通过控制器输入输出,这是正常的简单处理,其余还有)

    其中CPU主要的就是各种寄存器的集合体。

    这里写图片描述

    程序计数器是用于存放下一条指令所在单元的地址的地方。

    这里写图片描述

    上面是顺序执行,程序的流程还有条件分支、循环和函数调用的情况,条件分支是根据CPU的结果实现跳转,然后再依次顺序执行下去。循环是根据CPU的运行结果判断是否循环,循环结束后再依次执行后面的指令。函数调用是指先跳转到函数的内存地址,执行函数体指令(函数主体),函数执行完成后,返回到函数调用原点,再依次执行后面的指令。PS:这里的无论是按顺序还是实现跳转都是修改程序计数器内的地址来实现的。

    函数调用:通过call和return指令实现,在将函数的入口地址设定到程序计数器前,call指令会把调用函数后要执行的指令地址存储在名为栈(stack本意为“干草堆堆积如山”)的主存内。函数处理完毕后,再通过函数的出口来执行return命令。return命令的功能是把保存在栈中的地址设定到程序计数器中。

    附注:数组的起始地址是装在基址寄存器,而索引(偏移值)装在变址寄存器中。

    内存/CPU/寄存器/程序计数器关系:

    这里写图片描述

    第2章.数据是用二进制数据表示的

    1:32位是几个字节?

    4字节:8位为一个字节,所以是4个字节。
    

    2:二进制数0101 1100转换成十进制是多少?

    0*128+1*64+0*32+1*16 + 1*8+1*4+0*2+0*0 = 4+8+16+64 = 92:将二进制各位数与位权相乘再相加即可。
    

    3:二进制数0000 1111左移两位后,会变成原数的几倍?

    4被:因基数为2,左移1位即为原值两倍,所以左移2位为原值4倍。
    

    4:补码形式表示的8位二进制数1111 1111,用十进制数表示的话是多少?

    -1:因+1为1 0000 0000,9位,溢出一位,即为0,所以为-1;1111 1111的补数为求反加1,为0000 0001,因此补码表示的1111 1111为-1。
    

    5:补码形式表示的8位二进制数1010 1010,用16位的二进制数表示的话是多少?

    前面加8个1。此为符号扩充,符号扩充就是指在保持值不变的情况下将其转换成16位和32位的二进制数。不管是正数还是用补数表示的负数,都只需要用符号位的值(0或者1)填充高位即可。这就是符号扩充的方法。
    

    6:数值、字符串和图像等信息在计算机内部是以什么形式表现的?

    都是以二进制数值的形式来表现的。
    

    位是最小单位,字节是基本单位。内存和磁盘都使用字节单位来存储和读写数据,使用位单位则无法读写数据。因此字节是信息最基本的单位。

    这里写图片描述

    二进制数的值转化成十进制数的值,只需要将二进制数的各位的值和位权相乘,然后将相乘的结果相加即可。十进制的基数为10,二进制的基数为2。

    二进制数中表示负数值时,一般会把最高位作为符号来使用,因此我们把这个最高位称为符号位。符号位是0时表示正数,符号位是1时表示负数。

    补码:用正数来表示负数。

    补数求解的变换方法就是“取反+1”。例如1的二进制时00000001,因此-1就是先取反11111110,然后加1,就是11111111,所以1的补码就是11111111,也就是-1就是11111111。
    再举一例,11111110表示的负数是多少?我们可以利用负负得正这个性质。假若11111110是负A,那么11111110的补数就是正A,11111110的补数就是00000010,是2,所以11111110是-2。

    为什么要加1呢:因为任意一个数与它本身的位取反相加必定得到最大值,即每一位都是1。所以负数定义为取反加1,这样正负数相加就会刚好溢出,回到0的状态。

    右移位运算分为逻辑右移与算术右移。移动后最高位补0称为逻辑右移动。右移后最高位补原本最高位的值称为算术右移,也就是原来是正数补0,原来是负数补1,负数右移后依然是负数,正数右移后依然是正数。

    符号扩充:不管是正数还是用补数表示的负数,都只需用符号位的值(0或者1)填充高位即可。比如将0111111这个正的8位二进制数转换成16位二进制数时,是0000000001111111。11111111转成16位二进制数是1111111111111111。

    第3章:计算机进行小数运算时出错的原因

    计算机计算出错的原因:有一些十进制的小数无法转换成二进制数,就像下面这样,小数点后4位用二进制数表示时的数值范围0.0000-0.1111。能表示的数也只有下面几种,所以无法表示全部的十进制的小数。实际上,十进制数0.1转换成二进制后,会变成0.00011001100…(1100循环)这样的循环小数。

    这里写图片描述

    很多编程语言都提供两种表示小数的数据类型。分别是双精度浮点数和单精度浮点数(double、float)。双精度浮点说类型用64位、单精度浮点数用32位来表示全体小数。

    浮点数是指用符号、尾数、基数和指数四部分表示的小数。

    这里写图片描述
    双精度浮点数:
    符号部分[1位]指数部分[11位]尾数部分[52位];
    单精度浮点数:
    符号部分[1位]指数部分[8位]尾数部分[23位]。

    尾数部分用的是“将小数前面的值固定为1的正则表达式”。
    指数部分用的则是“EXCESS系统表现”。

    第4章:熟练使用有棱有角的内存

    1:有十个地址信号引脚的内存IC可以指定的地址范围是多少?

    能够表示2的十次冪个数据,十进制表示的话就是0-1023.
    

    2:高级编程语言中的数据类型表示的是什么?

    不仅仅表示存储在内存数据的数据的类型,还表示占据内存区域的大小。
    

    3:在32位内存地址的环境中,指针变量的长度是多少位?

    32位,指针指的是用来存储内存地址的变量,因此在32位内存地址的环境中必有32位。
    

    4:用LIFO方式进行数据读写的数据结构称为什么?

    栈,LIFO=Last In First Out.
    

    内存实际上是一种名为内存IC的电子元件。内存IC主要分为:ROM(Read Only Memory)只能用来读取的内存和RAM(Random Access Memory)可被读取和写入的内存。
    RAM又可分为需要经常刷新(refresh)以保存数据的DRAM(Dynamic RAM),以及不需要刷新电路既能保存数据的SRAM(Static RAM)。

    内存IC中有电源引脚、地址信号引脚、数据信号引脚、控制信号引脚等用于输入输出的大量引脚(IC的引脚)、通过为其指定地址(address),来进行数据的读写。

    那么,这个内存IC中能存储多少数据呢?数据信息引脚又D0~D7共八个,表示一次可以输入输出8位(=1字节)的数据。此外,地址信号引脚有A0~A9共十个,表示可以指定00000000~11111111共1024个地址。而地址用来表示数据的存储场所,因此我们可以得出这个内存IC中可以存储1024个1字节的数据。因此1024=1K,所以该内存IC的容量就是1KB。

    但是内存容量不可能只有1KB,但是一台计算机又不可能放入很多的内存IC,通常情况下,计算机使用的内存IC中会有更多的地址信号引脚,这样就能在一个内存IC中存储数十兆字节的数据。因此,只用数个内存IC,就可以达到512MB的容量。

    如我们想向内存内写入数据,则有:接通电源—>用地址引脚确定存储场所—>由数据引脚输入数据—>用WR或RD引脚决定写入或者读出。像WR和RD这样可以控制IC运行的信号称为控制信号,其中WR和RD同时为0时,写入和读出的操作都无法运行。

    内存可以把它假想成每层都存储着数据的楼房,例如可以这样想,内存为1KB时,表示的时如下的1024层楼房。
    这里写图片描述

    数据类型表示存储的何种类型的数据,从内存来看,就是占用的内存大小(占有的楼层数)的意思。即使是物理以1个字节为单位来逐一读写数据的内存,再程序中,通过指定其类型(变量的数据类型等),也能实现以特定字节数为单位进行读写。

    // 定义变量
    char a;
    short b;
    long c

    这三个变量的数据类型分别是,表示1字节长度的char,表示2字节长度的short,以及表示4字节长度的long。变量的数据类型不同,所占用的内存大小也不一样,如下图所示。

    这里写图片描述

    根据程序中指定的变量的数据类型的不同,读写的物理地址大小也会随之变化,这其实是非常方便的。假如程序中只能逐个字节地对内存进行读写,那该多么不便啊。

    理解指针地关键点就是要弄清数据类型这个概念。

    指针是一种变量,他所表示的不是数据的值,而是存储着数据的内存的地址。通过使用指针,就可以对任意指定地址的数据进行读写。

    -- 各种数据类型指针的定义
    char *d;
    short *e;
    long *f;

    这里写图片描述

    实际上,这些数据类型表示的是从指针存储的地址中一次能够读写的数据字节数。

    CPU是通过利用基址寄存器和变址寄存器来指定内存地址的。

    附注:Windows计算机上使用的程序通常都是32位(4字节)的内存地址。这种情况下,指针变量的长度也是32位。为什么会这样?因为指针变量是用来存储地址信息的,如果它的容量小于系统的地址大小,那么这个指针变量的用处就不大。所以指针变量的大小是=系统地址大小。那么为什么小于系统地址的大小就用处不大呢?因为最大寻址能力。

    数组是指多个同样数据类型的数据在内存中连续排列的形式。作为数据元素的各个数据会通过连续的编号被区分开来,这个编号被称为索引(index)。

    指定索引后,就可以对该索引所对应地址的内存进行读写操作。而索引和内存地址的变换工作由编译器自动实现(CPU是通过基址寄存器和变址寄存器来指定内存地址的)。

    -- 各种类型的数组定义
    char g[100];
    short h[100];
    long i[100];

    这里写图片描述

    栈和队列,都可以不通过指定地址和索引来对数组的元素进行读写。栈用的是LIFO(Last Input First Out,后入先出)方式,而队列用的则是FIFO(First Input First Out,先入后出)方式。

    二叉查找树是指在链表的基础上往数组中追加元素时,考虑到数据的大小关系,将其分成左右两个方向的表现形式。

    使用二叉查找树时,当目标数据比现在读出来的数据小时就可以转到左侧,反之目标数据较大时即可转到链表的右侧,这样就加快了找到目标数据的速度。

    第5章:内存和磁盘的亲密关系

    1:存储程序的方式指的是什么?

    在存储装置中保存程序,并逐一运行的方式。现代计算机采用的就是存储程序方式。
    

    2:通过使用内存来提高磁盘访问速度的机制称为什么?

    Disk Cache(磁盘缓存),磁盘缓存指的是,把从磁盘中读出的数据存储在内存中,当该数据再次被读取时,不是从磁盘而是从内存中直接高速读出。
    

    3:把磁盘的一部分作为假想内存来使用的机制称为什么?

    虚拟内存(virtual memory),借助虚拟内存哪怕是内存不足的计算机,也可以运行很大的程序。
    

    4:Windows中,在程序运行时,存储着可以动态加载调用的函数和数据的文件称为什么?

    DLL(DLL文件),Dynamic Link Liabrary的简称。
    

    5:在EXE程序文件中,静态加载函数的的方式称为什么?

    静态链接,函数的加载方式有静态链接和动态链接两种。
    

    6:在Windows计算机中,一般磁盘中1个扇区是多少字节?

    通常为512字节,扇区是磁盘保存数据的物理单位。
    

    利用电流来实现存储的内存,利用磁效应来实现存储的磁盘。

    存储程序方式:程序保存在存储设备中,通过有序地被读出来实现运行,这一机制称为存储程序方式。磁盘中存储的程序,必须要加载到内存后才能运行。在磁盘中保持的原始程序是无法直接运行的。(所以Windows双击打开一个程序文件就是把这个存储在硬盘上的文件加载到内存里面,然后看“任务管理器”内存消耗就变多了。结束某个程序,就是把加载到内存中的这个程序从内存中剔除。)

    磁盘缓存(disk cache):磁盘缓存指的是把磁盘中读出的数据存储到内存空间中来,这样当下一次需要读取同一数据时,就不用通过实际的磁盘,而是从磁盘缓存中把内容读出。这样可以大大改善磁盘数据的访问速度。

    把低速设备的数据保存到高速设备中,需要时可以直接将其从高速设备中读出,这种缓存的方式在其他情况下也会用到。其中的一个实例就是在Web服务器中使用。Web浏览器就可以把获取的数据暂时保存在磁盘中,然后在需要时再显示磁盘中的数据。也就是说,把低速网络数据保存到相对高速的磁盘中。

    虚拟内存(virtual memory):虚拟内存指的是把磁盘的一部分作为假想的内存来使用。虚拟内存虽说是把磁盘作为内存的一部分来使用,但实际上正在运行的程序部分,在这个时间点上必须存在在内存中。也就是说,为了实现虚拟内存,就必须把实际内存(也称物理内存)的内容,和磁盘上的虚拟内存的内容进行部分置换(swap),并同时运行程序。

    虚拟内存的方法有分页式和分段式两种。

    分页式虚拟内存的机制:
    这里写图片描述

    节约内存的编码方法:(1)通过DLL文件实现函数共有(2)通过调用_stdcall来减小程序文件的大小。

    扇区是对磁盘进行物理读写的最小单位。在Window的软件方面对磁盘进行读写的单位是扇区的整数倍簇(cu)1簇可以是1KB(两个扇区)、2KB、4KB等等。不过不同的文件不能存储在同一个簇中,否则就会导致有一方的文件不能被删除。因此不管多小的文件,都会占用1簇的空间。这样以来,所有的文件都会占用1簇的整数倍的磁盘空间。

    如果减少簇的容量,磁盘访问次数就会增加,就会导致读写文件的时间变长。

    磁盘是通过把其物理表面划分成多个空间来使用的。划分的方式分为扇区方式和可变长方形两种,一般使用的是扇区方式,把磁盘分为若干个同心圆的空间就是磁道。把磁盘按照固定大小(能存储的数据长度相同)划分成的空间就是扇区。

    展开全文
  • 程序怎么跑起来

    千次阅读 2018-05-06 10:39:00
    1、对程序员来说CPU是什么呢?内存是保存命令和数据的场所,通过地址来标记和指定。地址由整数值表示。CPU很内存是由许多晶体管组成的电子部件,通常称为IC(Integrated Circuit,集成电路)。CPU的内部由寄存器、...

    1、对程序员来说CPU是什么呢?

    内存是保存命令和数据的场所,通过地址来标记和指定。地址由整数值表示。

    CPU很内存是由许多晶体管组成的电子部件,通常称为IC(Integrated Circuit,集成电路)。CPU的内部由寄存器、控制器、运算器、和时钟四个部分组成,各个部分之间由电流信号相互连通。寄存器可用来暂存指令数据等处理对象。控制器负责把内存上的指令、数据读入寄存器、并更具指令的执行情况来控制计算机;运算器负责运算从内存读入寄存器的数据。时钟负责发出CPU开始计数的时钟信号。那么对于程序员来说CPU是什么呢?CPU是各种功能的寄存器的集合器。其中,程序计数器,累加寄存器、标志寄存器、指令寄存器和栈寄存器都只有一个、其他的寄存器会有多个。
    1.3决定程序流程的程序寄存器
    CPU每执行一个指令,程序计数器的值就会自动加一,(当执行的指令占据多个内存地址时,增加与指令长度相同的数值),然后,CPU的控制器就会参照程序计数器的数值,从内存中读取命令并执行。也就是说,程序计数器决定着程序的流程。
    1.4程序分支和循环机制
    程序的流程分为顺序执行,条件分支,和循环三种,顺序执行是按照地址内容的顺序执行指令。条件分支是指更具条件执行任意地址的指令。循环是指重复执行同一个地址的指令。条件分支和循环使用的跳转指令,会参照当前执行的运算结果来判断是否挑战。
     无论当前累加寄存器的运算结果是负数,0,正数,标志寄存器都会将其保存(也负责存放溢出,和奇偶校验的结果),CPU在进行运算的时候,标志寄存器的数值会更具结果自动设定。条件分支在跳转指令前会进行比较运算。至于是否执行跳转指令,则由CPU在参考 标志寄存器的数值后进行判断。标志计算器的第一个字节,第二个字节,第三个字节的值为1时,表示运算结果分别为正数,0,负数。

    CPU执行比较的机制很有意思。比如,假设要比较累加寄存器中存储的XXX值和通用寄存器中存储的YYY值,执行比较的指令后,CPU的运算装置就会在内部(暗中)进行XXX-YYY的减法运算。而无论减法运算的结果是正数,0,负数都会保存在标志寄寄存器中。

    1.5函数的调用机制

    不过,这和条件分支、循环的机制有所不同、因为单纯的跳转指令无法实现函数的调用。函数的调用需要在完成函数内部的处理之后,处理流程在返回到函数调用点(函数调用指令的下一个地址)。那么怎么办才好呢?


    机器语言的call指令和return指令能够解决这个问题。建议大家把二者结合起来记忆:函数调用使用的是call指令,而不是跳转指令。在将函数的入口地址设定到程序计数器之前,call指令会把调用函数要执行的指令地址在名为栈的主存内。函数处理完毕之后,在通过函数的出口来执行return命令。return命令的功能是把保存在栈中的地址设定到程序计数器中如下图所示:


    1.6通过地址和索引来实现数组

    我们通过基址寄存器和变址寄存器可以对主内存上特定的诶村区域进行划分,从而实现类似与数组的操作。

    首先,我们用十六进制数将计算机内存上00000000~FFFFFFFF的地址划分出来。那么,范式该范围的内存区域,只要有一个32位寄存器,即可查看全部的内存地址。但是若果想要向数组那样分割特定的内存区域已达到连续查看的目的,使用俩个寄存器会更加方便些。列如,产看10000000地址~1000FFFF地址时,如图1-9所示,


    将10000000存入基址寄存器,并使变址寄存器的值在00000000~0000FFFF变化,CPU则会把基址寄存器+变址寄存器的值解释为实际产看的内存地址。变址寄存器相当于高级编程语言中程序中数组的索引功能。

    1.7CPU的处理其实很简单

    机器语言指令的主要类型和功能如下:

    类型功能
    数据转送指令寄存器和内存、内存和内存、寄存器和外围设备之间的数据读写操作
    运算指令用累加寄存器执行算数运算、逻辑运算、比较运算和移位运算
    跳转指令实现条件分支、循环、强制跳转指令
    call/return指令函数的调用/返回调用前的地址

    (1)外围设备指的是连接到计算机的键盘、鼠标、显示器、设备装置、打印机等。

    第二章 数据是用二进制数表示的

    6、翻转部分图形模式时,使用的是什么逻辑?

    XOR运算。XOR运算之翻转与1相对应的位。NOT运算是翻转所有的位。

    2.1用二进制数标书计算机信息的原因

    想必大家都知道计算机内部是由IC这种电子部件构成的。第一章介绍的CPU(微处理器)和内存也是IC的一种。IC有几种不同的形状,有的像一条黑色蜈蚣,在其俩侧有数个乃至数百个引脚;有的像茶花用的针盘,引脚在IC内部并排排列着。IC的所有引脚,只有直流电压0V或者5V俩种状态。也就是IC的一个引脚,只能表示俩个状态。

    IC的这种特性,决定了计算机的信息数据只能用二进制来处理。由于1位(一个引脚)只能表示俩个状态,所以二进制的急速方式变成了0、1、10、11、、100。。。。之中形式。虽然二进制数并不是专门为IC设计的,但是和IC的特性非常吻合。计算机处理信息的最小单位是一位,就相当于二进制中的一位。位的英文bit是二进制数(binary digit)的缩写。

    二进制数的位数一般是8位,16位,32位。。。。也就是8的倍数,这是因为计算机所处理的信息的基本单位是8位二进制数。8位二进制数被称为一个字节。位是最小单位,字节是基本单位。内存和磁盘都是使用字节单位来存储和读写数据,使用位则无法读取数据 ,因此字节是信息的基本单位。

    2.5逻辑右移和算术右移的区别

    当二进制数的值表示图形模式而非数值时,移位后需要在最高位补0,类似与霓虹灯往右滚动的效果。这称为逻辑右移。

    将二进制数作为带符号的数值进行运算时,移位后要在最高位填充移位移位前符号位的值(0或者1);注意这里的高位布置是指最高位。就可以正常的实现1/2,1/4.。。。如果是正数,只需要在最高位补0.

    现在我们来看一个右移的列子:

    将-4(=11111100)右移俩位。这时,逻辑右移的情况下结果就会变成00111111,十进制是63,显然不是-4的1/4.而算术右移就会变成11111111,用补数表示就是-1.即-4的1/4。


    符号扩充:是指在保持值不变的前提下将其转换为16位和32位的二进制数。将01111111这个正的8位二进制转换成时16位二进制数时,很容易就能得出0000000001111111这个正确结果,但是像11111111这样的补数来表示的数值,该如何处理呢?其实很简单,将其表示成1111111111111111也就可以了。也就是不管正数还是用补数表示的负数,都只需要用符号位的值(0,或者1)填充高位即可。这就是符号扩充的方法。

    3.5 计算机运算出错的原因

    计算机之所以会出现运算错我,是因为“有一些十进制数的小数无法转化为二进制数”。列如,十进制数0.1,就无法用二进制数正确表示,小数点后面即使有几百位无法表示。接下来。我们来看一下不能正确表示的原因。

    小数点后4位用二进制数表示时的数值范围为0.0000~0.1111.因此,这里只能表示0.5,0.25,0.125、0。0625这四个二进制数小数点后面的位权组合而成(相加总和)的小数。将这些数值组合后嫩能够表示的数值,即为表3-1中所示的无需的十进制数。

    。因此这些中间的小数,就无法用小数点后四位数的二进制数来表示。同样0.0625的下一位数一下子变成了0.125.这时,如果增加二进制数小数点的个数也会增加,单不管增加多少位,怎么想家都无法得到0.1这个结果。在遇到循环小数时,计算机会根据变量的数据类型所对应的长度将数值从中间截断或者四舍五入。

    4.1内存的物理机制

    内存实际上是一种名为IC的电子元件。虽然内存IC包括DRAM(Dynamic Random Access Memory )动态随机存储器,SRAM(Static Random Access Memory)(静态随机存储器),ROM,等多种形式,但是从外部来看,其基本机制都是一样的。内存IC中有点源,地址信号,数据信号,控制信号等用于输入输出的大量引脚(IC引脚),通过为其制定地址(Address)l来进行数据的读写。


    将电晕啊连接到VCC和GND后,就可以给其他引脚传递比如0或者1这样的信号。那么这个内存IC能存储多少数据呢?数据信号引脚有D0~D7共八个,表示一次可以输入或者输出8位(1字节)的数据。此外,地址信号引脚有A0~A9共十个,表示可以指定1024个地址。而地址是用来表示数据的存储场所,因此我们可以的出这个内存IC中可以储存1024=1k,所以改内存的IC的容量就是1kb.

    现在计算机至少有512M内存。就相当于512000个1KB的内存IC。发当然,一台机器不可能放入如此多的内存IC。通常情况下,计算机使用的内存IC中会有更多的地址信号引脚,这样就能在一个内存IC中存储数十兆字节的数据。因此,只用数个内存,就可以达到512MB的容量。


    通过上图可知:内存IC的物理就只很简单,总体来讲,内存IC内部有大量可以存储8位数据的地方,通过地址指定这些场所,之后就可以进行数据的读写。

    5. 虚拟内存把磁盘作为部分内存来使用。

    虚拟内存是指把磁盘的一部分作为假想的内存来使用。者与磁盘缓存是假想的磁盘相对,迅内存是假想的内存。

    展开全文
  • 寒假过半,今天正好是第三周的周末,读完了《程序怎样跑起来的》。最近很少做手撕代码的事,却读了一些基础知识相关的书。俗话说,快就是慢,慢就是快。不要一味追求代码代码,最后却忘了本质的东西。 &nbsp;&...
  • 程序怎样跑起来

    热门讨论 2018-10-02 21:40:34
    写在前面
  • 本书从计算机的内部结构开始讲起,以图配文的形式详细讲解了二进制、内存、数据压缩、源文件和可执行文件、操作系统和应用程序的关系、汇编语言、硬件控制方法等内容,目的是让读者了解从用户双击程序图标到程序开始...
  • 《程序是怎样跑起来的》学习笔记前言1. 对程序员来说CPU是什么1.1. CPU的内部结构解析1.2. CPU是寄存器的集合体1.3. 决定程序流程的程序计数器1.4. 条件分支和循环机制1.5. 函数的调用机制1.6. 通过地址和索引实现...
  • 读了《程序怎么跑起来的》第一章,使我对CPU有了更深的了解,文中详细的介绍了CPU的结构和程序的运行机制,以及条件分支和循环机制,也让我明白了为什么用二进制表示信息,而文中强调在CPU的四个构成部分中,...
  • 想对计算机系统做些深入了解,故整了几本书翻翻,这里做个记录。 从《程序怎样跑起来的》开始,本节是第一章:CPU是什么。
  • 继续翻览《程序怎样跑起来的》,本节是第九章:操作系统和应用的关系
  • 本书从计算机的内部结构开始讲起,以图配文的形式详细讲解了二进制、内存、数据压缩、源文件和可执行文件、操作系统和应用程序的关系、汇编语言、硬件控制方法等内容,目的是让读者了解从用户双击程序图标到程序开始...
  • 操作系统的硬件控制功能...在前面的程序中用到了time()及printf()等函数,这些函数内部也都使用了系统调用。这里之所以用“内部”这个词,是因为在Windows操作系统中,提供返回当前日期和时刻,以及在显示器中显示字...
  • 程序怎样跑起来

    2018-03-30 19:06:51
    简单说一下,可执行程序是什么的,编译链接过程,操作系统和CPU执行过程。...《程序怎样跑起来的》一书 gcc常用命令:http://man.linuxde.net/gcc 汇编差异:https://wenku.baidu.com/view/8888bf84b9d52...
  • cpu是寄存器的合体,当然除了寄存器还有其他的控制器,计算器,时钟,这不讨论,寄存器有多种类型 :【累加寄存器,程序计数器,标志寄存器,基址寄存器,变址寄存器,通用寄存器】等 2. 其中程序计数器控制着下...
  • 继续翻览《程序怎样跑起来的》,本节是第七章:程序运行环境
  • 程序怎样跑起来

    2020-03-14 18:23:45
      在程序员的开发中,使用的语言基本都是类似C、Java、Python等高级编程语言,那么我们日常编写的代码是如何在计算机上跑起来的呢?今天,就让我们一起来捋一捋程序跑起来的过程。 一、计算机组成 ​  现代...

空空如也

1 2 3 4 5 ... 20
收藏数 209,804
精华内容 83,921
关键字:

程序是怎样跑起来的