C 语言程序成为高级语言的原因是它能够读取并理解人们的思想。然而,为了能够在系统中运行 hello.c 程序,则各个 C 语句必须由其他程序转换为一系列低级机器语言指令。这些指令被打包作为可执行对象程序,存储在二进制磁盘文件中。目标程序也称为可执行目标文件。

在 UNIX 系统中,从源文件到对象文件的转换是由编译器执行完成的。

gcc -o hello hello.c

gcc 编译器驱动从源文件读取 hello.c ,并把它翻译成一个可执行文件 hello。这个翻译过程可用如下图来表示

这就是一个完整的 hello world 程序执行过程,会涉及几个核心组件:预处理器、编译器、汇编器、连接器,下面我们逐个击破。

预处理阶段(Preprocessing phase),预处理器会根据开始的 # 字符,修改源 C 程序。#include <stdio.h>命令就会告诉预处理器去读系统头文件 stdio.h 中的内容,并把它插入到程序作为文本。然后就得到了另外一个 C 程序hello.i,这个程序通常是以 .i为结尾。

然后是 编译阶段(Compilation phase),编译器会把文本文件 hello.i 翻译成文本hello.s,它包括一段汇编语言程序(assembly-language program)。

编译完成之后是汇编阶段(Assembly phase),这一步,汇编器 as会把 hello.s 翻译成机器指令,把这些指令打包成可重定位的二进制程序(relocatable object program)放在 hello.c 文件中。它包含的 17 个字节是函数 main 的指令编码,如果我们在文本编辑器中打开 hello.o 将会看到一堆乱码。

最后一个是链接阶段(Linking phase),我们的 hello 程序会调用 printf 函数,它是 C 编译器提供的 C 标准库中的一部分。printf 函数位于一个叫做 printf.o文件中,它是一个单独的预编译好的目标文件,而这个文件必须要和我们的 hello.o 进行链接,连接器(ld) 会处理这个合并操作。结果是,hello 文件,它是一个可执行的目标文件(或称为可执行文件),已准备好加载到内存中并由系统执行。

你需要理解编译系统做了什么

对于上面这种简单的 hello 程序来说,我们可以依赖编译系统(compilation system)来提供一个正确和有效的机器代码。然而,对于我们上面讲的程序员来说,编译器有几大特征你需要知道

优化程序性能(Optimizing program performance),现代编译器是一种高效的用来生成良好代码的工具。对于程序员来说,你无需为了编写高质量的代码而去理解编译器内部做了什么工作。然而,为了编写出高效的 C 语言程序,我们需要了解一些基本的机器码以及编译器将不同的 C 语句转化为机器代码的过程。

理解链接时出现的错误(Understanding link-time errors),在我们的经验中,一些非常复杂的错误大多是由链接阶段引起的,特别是当你想要构建大型软件项目时。

避免安全漏洞(Avoiding security holes),近些年来,缓冲区溢出(buffer overflow vulnerabilities)是造成网络和 Internet 服务的罪魁祸首,所以我们有必要去规避这种问题。

系统硬件组成

为了理解 hello 程序在运行时发生了什么,我们需要首先对系统的硬件有一个认识。下面这是一张 Intel 系统产品的模型,我们来对其进行解释

总线(Buses):在整个系统中运行的是称为总线的电气管道的集合,这些总线在组件之间来回传输字节信息。通常总线被设计成传送定长的字节块,也就是 字(word)。字中的字节数(字长)是一个基本的系统参数,各个系统中都不尽相同。现在大部分的字都是 4 个字节(32 位)或者 8 个字节(64 位)。

I/O 设备(I/O Devices):Input/Output 设备是系统和外部世界的连接。上图中有四类 I/O 设备:用于用户输入的键盘和鼠标,用于用户输出的显示器,一个磁盘驱动用来长时间的保存数据和程序。刚开始的时候,可执行程序就保存在磁盘上。 每个I/O 设备连接 I/O 总线都被称为控制器(controller) 或者是 适配器(Adapter)。控制器和适配器之间的主要区别在于封装方式。控制器是 I/O 设备本身或者系统的主印制板电路(通常称作主板)上的芯片组。而适配器则是一块插在主板插槽上的卡。无论组织形式如何,它们的最终目的都是彼此交换信息。

主存(Main Memory),主存是一个临时存储设备,而不是永久性存储,磁盘是 永久性存储 的设备。主存既保存程序,又保存处理器执行流程所处理的数据。从物理组成上说,主存是由一系列 DRAM(dynamic random access memory) 动态随机存储构成的集合。逻辑上说,内存就是一个线性的字节数组,有它唯一的地址编号,从 0 开始。一般来说,组成程序的每条机器指令都由不同数量的字节构成,C 程序变量相对应的数据项的大小根据类型进行变化。比如,在 Linux 的 x86-64 机器上,short 类型的数据需要 2 个字节,int 和 float 需要 4 个字节,而 long 和 double 需要 8 个字节。

处理器(Processor),CPU(central processing unit) 或者简单的处理器,是解释(并执行)存储在主存储器中的指令的引擎。处理器的核心大小为一个字的存储设备(或寄存器),称为程序计数器(PC)。在任何时刻,PC 都指向主存中的某条机器语言指令(即含有该条指令的地址)。 从系统通电开始,直到系统断电,处理器一直在不断地执行程序计数器指向的指令,再更新程序计数器,使其指向下一条指令。处理器根据其指令集体系结构定义的指令模型进行操作。在这个模型中,指令按照严格的顺序执行,执行一条指令涉及执行一系列的步骤。处理器从程序计数器指向的内存中读取指令,解释指令中的位,执行该指令指示的一些简单操作,然后更新程序计数器以指向下一条指令。指令与指令之间可能连续,可能不连续(比如 jmp 指令就不会顺序读取) 下面是 CPU 可能执行简单操作的几个步骤

加载(Load):从主存中拷贝一个字节或者一个字到内存中,覆盖寄存器先前的内容

存储(Store):将寄存器中的字节或字复制到主存储器中的某个位置,从而覆盖该位置的先前内容

操作(Operate):把两个寄存器的内容复制到 ALU(Arithmetic logic unit) 。把两个字进行算术运算,并把结果存储在寄存器中,重写寄存器先前的内容。

算术逻辑单元(ALU)是对数字二进制数执行算术和按位运算的组合数字电子电路。

跳转(jump):从指令中抽取一个字,把这个字复制到程序计数器(PC) 中,覆盖原来的值

剖析 hello 程序的执行过程

前面我们简单的介绍了一下计算机的硬件的组成和操作,现在我们正式介绍运行示例程序时发生了什么,我们会从宏观的角度进行描述,不会涉及到所有的技术细节。

刚开始时,shell 程序执行它的指令,等待用户键入一个命令。当我们在键盘上输入了 ./hello 这几个字符时,shell 程序将字符逐一读入寄存器,再把它放到内存中,如下图所示

当我们在键盘上敲击回车键的时候,shell 程序就知道我们已经结束了命令的输入。然后 shell 执行一系列指令来加载可执行的 hello 文件,这些指令将目标文件中的代码和数据从磁盘复制到主存。

利用 DMA(Direct Memory Access) 技术可以直接将磁盘中的数据复制到内存中,如下

一旦目标文件中 hello 中的代码和数据被加载到主存,处理器就开始执行 hello 程序的 main 程序中的机器语言指令。这些指令将 hello,world\n 字符串中的字节从主存复制到寄存器文件,再从寄存器中复制到显示设备,最终显示在屏幕上。如下所示

高速缓存是关键

上面我们介绍完了一个 hello 程序的执行过程,系统花费了大量时间把信息从一个地方搬运到另外一个地方。hello 程序的机器指令最初存储在磁盘上。当程序加载后,它们会拷贝到主存中。当 CPU 开始运行时,指令又从内存复制到 CPU 中。同样的,字符串数据 hello,world \n 最初也是在磁盘上,它被复制到内存中,然后再到显示器设备输出。从程序员的角度来看,这种复制大部分是开销,这减慢了程序的工作效率。因此,对于系统设计来说,最主要的一个工作是让程序运行的越来越快。

由于物理定律,较大的存储设备要比较小的存储设备慢。而由于寄存器和内存的处理效率在越来越大,所以针对这种差异,系统设计者采用了更小更快的存储设备,称为高速缓存存储器(cache memory, 简称为 cache 高速缓存),作为暂时的集结区域,存放近期可能会需要的信息。如下图所示

图中我们标出了高速缓存的位置,位于高速缓存中的 L1高速缓存容量可以达到数万字节,访问速度几乎和访问寄存器文件一样快。容量更大的 L2 高速缓存通过一条特殊的总线链接 CPU,虽然 L2 缓存比 L1 缓存慢 5 倍,但是仍比内存要更快 5 - 10 倍。L1 和 L2 是使用一种静态随机访问存储器(SRAM) 的硬件技术实现的。最新的、处理器更强大的系统甚至有三级缓存:L1、L2 和 L3。系统可以获得一个很大的存储器,同时访问速度也更快,原因是利用了高速缓存的 局部性原理。

最后,如果你也想成为程序员,想要快速掌握编程,赶紧加入学习企鹅圈子!

里面有资深专业软件开发工程师,在线解答你的所有疑惑~编程语言入门“so easy”

编程学习书籍:

编程学习视频:

走进C 语言:你知道C语言程序是如何执行的吗?相关推荐

  1. 单片机c语言编译过程,单片机C程序编译、执行过程

    1.编写C代码: 1)预编译代码 2)定义及声明变量 3)定义及声明函数 4)编写程序代码(主函数MAIN) 2.编译器编译: 1) 预处理 此时编译器会扫描一个一个的C源文件,如果发现#includ ...

  2. c语言小饭店等位就餐程序,C语言程序设计 C语言程序设计 3.C语言程序设计教案全部.doc...

    C语言程序设计教案 PAGE PAGE 2 C语言程序设计教案 C语言程序设计教案 编写:宋铁桥 计算机技术系 二〇一七年三月整理 河北工业职业技术学院 <C语言程序设计>课程教案首页 授 ...

  3. c语言编程 构建围墙,c语言程序设计朝盛 综合程序练习题.ppt

    c语言程序设计朝盛 综合程序练习题 综合程序练习题 综合程序练习题 大型程序设计的要求 综合程序练习题 综合程序练习题 大型程序设计题目分析: 1 打字练习 2 电子琴 3 简易画图板 4 贪吃蛇 5 ...

  4. python是c语言写的吗-先学C语言还是Python?资深程序员往往是这样建议的!

    编程是一门手艺, 学习编程首先要有目的,w3cschool先带大家了解一下自己需要学习什么吧! 0.学一门语言 其实学什么语言都可以,因为语言都是互通的,C语言也好, 对于初学者来说,Python 也 ...

  5. 没学c语言可以学python_先学C语言还是Python?资深程序员往往是这样建议的!

    编程是一门手艺, 学习编程首先要有目的,w3cschool先带大家了解一下自己需要学习什么吧! 0.学一门语言 其实学什么语言都可以,因为语言都是互通的,C语言也好, 对于初学者来说,Python 也 ...

  6. 换硬币c语言编程_为什么大多数程序员都会学C语言的5大原因!什么原因让你学不会?...

    一.c语言,不朽的传奇 从30年前到如今,一些流行的科技媒体上发表的编程语言排行榜,c语言始终稳定位于前三位,这是其他一种其他的编程语言都达不到的.c语言的江湖地位,不容撼动.虽历史悠久,却也是不朽的 ...

  7. C语言基础-第一个C程序

    之前在大学期间学过C语言的基础,后来主要方向是java,就没继续深入学习C语言.但是C语言作为一个基础语言,对开发有着很大的帮助.最近又开始用业余时间系统的学习C语言. 首先,简单的介绍一下C语言 C ...

  8. 图像haar特征提取 c语言,基于C语言的特征点提取程序 本程序是利用C语言对各种信号数据的特征点提取程序 - 下载 - 搜珍网...

    基于C语言的特征点提取程序\修改后 特征点提取程序\提取特征点\Debug\football.ilk 基于C语言的特征点提取程序\修改后 特征点提取程序\提取特征点\Debug\football.ob ...

  9. c语言求成绩标准差,C程序计算标准偏差

    C程序计算标准偏差 在此示例中,您将学习使用数组计算10个数字的标准偏差. 要理解此示例,您应该了解以下C语言编程主题: 该程序使用数组计算单个系列的标准偏差.为了计算标准差,我们创建了一个名为cal ...

  10. c语言烟花百度云,C语言实现放烟花的程序

    这是一个利用C语言编写放烟花的程序(同时也可以播放音乐),供大家参考,具体内容如下 代码如下 #pragma once #include #include //图形界面库头文件 #include // ...

最新文章

  1. 14 个 Spring MVC 顶级技巧,随时用随时爽,一直用一直爽
  2. 按原有结构恢复被删除的FAT32文件夹
  3. 大流量高并发量网站的之解决方案
  4. ssl2290-潜水员【dp之二维费用】
  5. leetcode 491. 递增子序列 思考分析
  6. php 五角星,php使用GD库画五角星_PHP教程
  7. c语言程序设计语言描述,C语言程序设计题目描述(详).txt
  8. 【转载】用java压缩文件夹/文件
  9. 【LeetCode】Remove Nth Node From End of List
  10. 四川大学锦城学院计算机考试题,四川大学锦城学院期考试试题(B卷)_15889.doc
  11. JDK1.5英文版CHM文档下载地址
  12. 屋子里有1到100号100盏关闭的灯
  13. Hbase记录-client访问zookeeper大量断开以及参数调优分析(转载)
  14. How to extract datafiles from asm diskgroup?
  15. 遥感图像计算机分类论文,遥感影像和监督分类论文,关于基于监督分类的土地利用遥感影像提取方法相关参考文献资料-免费论文范文...
  16. 文件夹的隐藏选项为灰色勾选,无法更改或删除
  17. Javascript Promise用法详解
  18. 计算机错误678,宽带连接错误678,教您宽带连接错误678怎么解决
  19. 牛客算法課 (算法入門班) 二分, 三分, 01分數規劃
  20. 突破asa,cer,cdx,php,aspx 上传

热门文章

  1. 对camera的计划
  2. java遍历变量_java – 循环遍历众多变量
  3. Android主流HOOK框架介绍与应用--游戏破解游戏外挂的必杀技
  4. 重磅来袭!怎么用java编写app软件
  5. 学会java足够开发app吗_请问如何两个月内在不懂java 的情况下学会开发app?
  6. 第3期——WLAN标准协议
  7. Unity经纬度相互转换(WGS-84、GCJ-02、BD-09)
  8. 计算机怎样发现路由器上u盘,360 P2 无线路由器通过电脑终端查看路由USB存储设备操作流程 路由器...
  9. 读《深入浅出MySQL数据库开发、优化与管理维护(第2版)》笔记1
  10. webdav同步书签-floccus