C语言程序从编写到运行历经的几个阶段

一 前言

  在完成 .c 或 .cpp 文件的编写后,我们通常直接 gcc 或 g++ 后接文件名,就可以在当前文件夹下生成 a.out 可执行文件, 之后输入 ./a.out 即可执行该二进制可执行文件。
  但实际上C语言程序从编写到运行,这期间的经历并不是这么简单,那么现在小编就带领大家探索,这期间具体有哪几个步骤?

一 过程简介


  从上图可知从C源码到可执行程序,我们会历经三个步骤,分别是:预处理阶段、编译阶段以及最后的链接阶段。但是如果我们分的更细一点,其实我们可以分成四个步骤:

显然由图片我们可以知道经历的四个步骤是:预处理、编译、汇编、链接
通常gcc命令后面不加选项的话,就会默认执行预处理、编译、汇编、链接所有步骤,若程序没有错误的话,我们就可以得到一个可执行文件,默认为 a.out, 这也是小编在前言中说的。
-E选项:编译器执行完预处理阶段就停止执行,后面的编译、汇编等操作就不会执行。
-S选项:编译器执行完编译阶段就会停止。
-c选项:编译器执行完汇编阶段就会停止。
其实,这三个阶段只是限定了编译器执行操作的截止时间,而不是单独的将某一步拎出来执行。

二 预处理阶段

执行 gcc -E hello.c > hello.i 命令后,我们仅仅执行预编译操作,生成一个.i 文件 (这个文件是我们最后还可以读得懂的文件了,我们可以打开这个文件,仔细观察程序出现了哪些变化)

那么预处理阶段都进行了哪些操作呢?

  1. 对所有以 # 开头的语句进行处理,其中包括我们熟知的:#define、#include <xxx.h>、条件编译指令#ifdef等。
  2. 删除所有的“/**/”和“//”注释。
  3. 添加行号和文件名标识,方便编译器产生的调用以及当出现编译错误或者是警告时可以显示行号。
  4. 保留所有的 #pragma 编译指令

这里小编想着重阐述的是第一部分!!!

程序中以“#include”开头的语句都会被替换成相应头文件中的内容 (也就是说,项目中不论是自己写的 被#include ""引用的.h 头文件还是系统自带的#include <> 头文件,在预处理阶段阶段之后都会消失,并且这个过程是递归进行的,因为被包含的文件还有可能包含了其他文件,同时为了避免头文件的重复包含,我们引入了#ifdef,#ifndef等条件编译指令,这里就不细说)。
此外程序中的#define 定义的宏在使用的地方都会进行替换 (大家不要小看宏定义,这决不仅是 #define PI 3.14之后进行使用这么简单)
关于宏定义的其他操作如下:

还有系统已经定义好的宏,我们可以直接拿过来使用



在这里小编想强调两点:

  • 宏 只是替换
    例如我们上图中定义: #define S(a, b) a * b,这显然是用来求乘积的,那我们现在在程序中调用它最终的结果是什么呢?
    例如:S(5, 3 + 1),最后的结果会是: 5 * 4 = 20 吗?
    显然不是,这条语句会被替换成:5 * 3 + 1,所以最终的答案是 16 !!!
    同时也因为只是替换,所以宏替换不会占用程序的运行时间。
  • 可以通过宏 定义代码段
    在这里大家可以粗略的理解成 “宏可以产生代码”。
    至于每一行语句的最后需要加上反斜杠,这是因为宏定义只可以出现在一行,所以我们才使用 '\'进行连接。

三 编译阶段

使用 -S选项,编译器执行完编译阶段就结束,最后形成 .s 文件

应该说编译阶段是整个程序从C到机器语言翻译过程的核心,我们之前学习的编译原理这门课中讲到的词法分析、语法分析、语义分析以及之后的优化等其他操作, 其实就是在这个阶段执行的。

四 汇编阶段

使用 -c 选项,编译器执行完汇编阶段就结束,形成 .o (windows下为 .obj ) 对象文件。
其中汇编器将会汇编代码转换为机器可识别的机器代码,之前项目中有几个 source.c 文件,此时就会出现几个对象文件

五 链接阶段

前一个阶段我们得到了若干个对象文件,现在我们要做的就是将这几个对象文件链接起来,形成最后的可执行文件。
(这其中还涉及到静态链接库和动态链接库的概念,若想了解,请点击我)


(20220311更新) 静态链接库和动态链接库代码演示:

  静态链接和动态链接的区别在于:对函数库的链接是在编译期完成还是程序运行时期完成,若是编译期间则是静态链接,对应的函数库就是静态链接库 (linux下为.a文件,win下为.lib文件),若是在运行时期完成,则为动态链接,对应的函数库就是动态链接库 (linux下为.so文件,win下为.dll文件),不论静态链接库还是动态链接库,都是由若干个对象文件构成的。
  闲话不多说,我们先写一些演示代码 (先演示静态链接库后演示动态链接库),如下分别创建:add.h、add.cpp、sub.h、sub.cpp、main.cpp 五个文件,文件内容如下:

/* sub.h 文件内容 */
#ifndef _SUB_H
#define _SUB_H
int sub(int, int);
#endif/* sub.cpp 文件内容 */
#include "sub.h"int sub(int x, int y) {return x - y;
}/* add.h 文件内容 */
#ifndef _ADD_H
#define _ADD_H
int add(int, int);
#endif/* add.cpp 文件内容 */
#include "add.h"int add(int x, int y) {return x + y;
}/* main.cpp 文件内容 */
#include "sub.h"
#include "add.h"
#include <iostream>
using namespace std;int main() {cout << "1 + 2 = " << add(1, 2) << endl;cout << "1 - 1 = " << sub(1, 2) << endl;return 0;
}

(1) 编译和使用静态链接库过程如下:

  大致过程为:将 add.cpp 和 sub.cpp 文件分别编译为对象文件,然后将其打包为静态链接库,之后再和main.cpp一块编译获得可执行文件。

(2) 编译和使用动态链接库过程如下:

  大致过程为:将 add.cpp 和 sub.cpp 文件分别编译为对象文件,然后将其打包为动态链接库 (.so文件) ,若没有使用sudo cp libmymath.so /lib却直接运行./main可执行文件,将会报错,显示找不到动态链接库No such file or directory,这是因为默认情况下,编译器只会使用/lib和/usr/lib这两个目录下的库文件。故此处将.so文件添加到了/usr/lib目录下。


至此,我们的阐述就结束了。加油,路漫漫其修远兮,吾将上下而求索,与君共勉!!!

C语言程序从编写到运行历经的几个阶段相关推荐

  1. 在C语言上如何编写并运行MPI程序

    一.安装MPI 第一步:下载MPI软件包 得到文件: mpich.nt. 1.2.5.zip 第二步:安装 1.解压缩文件mpich.nt.1.2.5.zip到目录mpich.nt.1.2.5 2.进 ...

  2. Ubuntu下C语言程序的编写

    Ubuntu下C语言程序的编写 要求:请编写一个主程序文件 main1.c 和一个子程序文件 sub1.c, 要求:子程序sub1.c 包含一个算术运算函数 float x2x(int a,int b ...

  3. 零基础学习PHP编程——程序的编写和运行过程

    零基础学习PHP编程--程序的编写和运行过程 注意: 本文主要写给零基础的同学,作为编程的入门引导, 如有不当之处,还请指正. 访问源站 欢迎交流QQ群: 640765823 回顾上一节,我们已经基本 ...

  4. C语言 程序代码编写规范

    前言 一个好的程序编写规范是编写高质量程序的保证.清晰.规范的源程序不仅仅是方便阅读,更重要的是能够便于检查错误,提高调试效率,从而最终保证软件的质量和可维护性. 说明 l 本文档主要适用于刚刚开始接 ...

  5. c语言程序前言,C语言 程序代码编写规范前言

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 一个好的程序编写规范是编写高质量程序的保证.清晰.规范的源程序不仅仅是方便阅读,更重要的是能够便于检查错误,提高调试效率,从而最终保证软件的质量和可维护性 ...

  6. c语言程序报告的前言,C语言 程序代码编写规范前言

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 一个好的程序编写规范是编写高质量程序的保证.清晰.规范的源程序不仅仅是方便阅读,更重要的是能够便于检查错误,提高调试效率,从而最终保证软件的质量和可维护性 ...

  7. Java程序从编写到运行

            Java程序从开发到运行包括编译和运行两个阶段,这两个阶段可以在不同的操作系统中完成,例如在windows环境下进行编译,在Linux环境下运行,这是因为有JVM机制的存在,实现了Ja ...

  8. C语言——C语言程序的编写

    第一讲.C语言程序的编写 一.开发工具的选择 1)可以用来写代码的工具,记事本.ULtraEdit.Vim.Xcode等 2)选择Xcode的原因:苹果官方提供的开发利器.简化开发过程.有高亮显示功能 ...

  9. Ubuntu下bpf纯c程序的编写与运行

    1. 前言 搭建bpf运行环境真的是很费时间,踩过的坑也不少,今天也是因为虚拟机扩容崩了,重新安装了最新的ubuntu,bpf运行环境得以搭建完成,也算是破而后立.现在将bpf运行环境搭建和bpf纯c ...

最新文章

  1. 2005-3-28 + 探索ASP.NET Forum (1) 最初的印象
  2. Deploying Windows Mobile 6 with Exchange Server 2007 白皮书
  3. 【Android 逆向】Android 进程简介 ( Android 应用启动流程 )
  4. Hystrix指标窗口实现原理
  5. php 企业微信指令回调借款_php处理微信支付回调改变订单支付状态的代码
  6. 看下资深架构师平时需要解决的问题,对比你离资深架构师还有多少距离——再论技术架构的升级之路...
  7. 3.7.6 - String Methods
  8. Android 快速修复功能,用于解决Android系统问题的四大Android修复软件
  9. 关于ISI、SCI、EI、IEEE、Elsevier、Springer的区别
  10. linux去除文件中重复行,2.25 uniq(检查及删除文本文件中重复出现的行列)
  11. PS教程:逼真的模特投影
  12. unity批量设置图片为etc2格式或者astc格式
  13. Centos7安装gos脚本
  14. Android UI自动化工具-SoloPi
  15. 使用nodejs机器学习进行app流量判别
  16. android:手机与BLE-CC41-A蓝牙模块通信
  17. Halcon入门(1)——选取ROI区域
  18. vue 输入中文转拼音首字母(附转大写)
  19. js按下回车键调用方法
  20. 优化问题---最优性条件

热门文章

  1. Noise Contrastive Estimation 前世今生——从 NCE 到 InfoNCE
  2. [随笔]2019年总结 2020年计划
  3. Face Alignment
  4. DevOps 与研发效能专家张乐:研发效能的升维思考与降维执行
  5. softmax的log似然代价函数(公式求导)
  6. Firefox火狐浏览器使用小技巧
  7. python从右向左第三个字符_字符串是一个字符序列,例如,字符串s,从右侧向左第3个字符用________索引。...
  8. 小陈学vue.js 过滤器
  9. [AHK]Excel 怎么使用鼠标滚轮控制表格左右移动
  10. Google打不开的解决方法和部分Google镜像IP地址表