首页 > 程序的编译和链接过程

程序的编译和链接过程

一.虚拟机、linux简介
简单介绍一下虚拟机还有就是各种操作系统,比如centos,Ubuntu
操作系统:linux(centos、Ubuntu、redhat),Android,Windows(xp、win8、win10)
进程,多个程序,分时技术,并行技术
一次打开多个程序,我们在只有一个cpu,如何让这些程序进行执行呢,看起来好像是在同时进行的,实际上是一个程序执行了一点点时间,然后保存执行的一些信息,接下来回来再次执行,这样就达到了看上去是多个程序在同时执行的效果
操作系统的作用:控制程序的执行,管理系统的资源


二.程序的编译链接过程


2.1首先看一下预处理的指令




关于上面的预处理指令,大家可以自己测试一下


(测试例子)(注意是两行)
ANSI 标准 C 定义的几个宏如下,大家可以简单的了解一下
__LINE__ 表示正在编译的文件的行号
__FILE__ 表示正在编译的文件的名字
__DATE__ 表示编译时刻的日期字符串,例如: "25 Dec 2007"
__TIME__ 表示编译时刻的时间字符串,例如: "12:30:55"
__STDC__ 判断该文件是不是定义成标准 C 程序


2.2宏定义
编译器在预处理的时候,就会把宏定义的数据替换成它的元身,这里我们必须了解什么是宏,宏的主要的用法
2.2.1 定义宏常量
#define PI 3.14159265358979323846264338327
比如我们经常使用的一个变量,如果这个变量的数值改变了之后,我们不需要再文件里面一个一个找,而是只需要把宏改变就可以了
#define ERROR_TEST -1
比如我们在test文件中,一些代码的地方需要使用return -1,或者是exit(-1)
然后有很多类型的错误返回,如果每次返回的是-1,-2,-3之类的,一会就把自己给绕晕了
2.2.2定义字符串常量
#define PATH "c/file/linux"
这个一般用在表示文件的路径的情况下有很多
(大家下去看一下,如果是一行写不下怎么办呢,就是比如一行太长了怎么办)
2.2.3 定义注释
#define ZZ //
因为在程序编译的时候,注释是先于宏处理的
2.2.4 定义表达式(宏函数)
#define MUL(x) x*x
纯文本替换
测试用例
MUL(5);MUL(1+2); --- 加上括号MUL((x)*(x))
MUL(5*3)*MUL(5*3) --- 大括号???不要吝啬括号
2.2.5 空格
#define MUL (x) ((x)*(x))
比如上面的宏函数,我们要是定义成下面的这个样子又是什么样的呢
2.2.6#undef
撤销宏定义
比如
#define PI 3.14159265358979323846264338327
...
...
...
#undef PI此时PI不在有效了
2.2.7定义宏函数补充
比如下面的程序
#define PRINTF printf("测试");


这个时候我们可以编写 一个if esle语句
if(0)
PRINTF;
else
printf("haha ");


宏函数比普通函数的一些特性在哪里
(1)普通的函数需要建立栈帧,开销较大,宏函数在效率上面更胜一筹
(2)函数中的参数必须使用特定的类型,换句话说,宏函数对参数是不进行类型检查的,宏函数是不类型限制的


宏函数的缺点
宏函数每次是进行的代码的替换,有时候可能会增加代码的长度,使维护起来非常的复杂
宏函数的参数不能是一个类型


2.3. 条件编译
第一种形式:
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
它的功能是,如果标识符已被 #define 命令定义过则对程序段 1 进行编译;否则对程序段 2
进行编译。


第二种形式
#ifndef
标识符程序段 1
#else
程序段 2
#endif


第三种形式
#if 常量表达式
程序段 1
#else
程序段 2
#endif




2.4. 文件包含
文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结果将生成一个目标文件。C语言提供#include 命令来实现文件包含的操作,它实际是宏替换的延伸,有两种格式:
#include
#include"filename"
2.5.#pragma 预处理
自己上网调研,写博客,写测试用例
#pragma once
#pragma warning
#pragma pack--这个是张晨亮学长给你们讲过的,设置内置内存对齐数




2.6详解程序编译和链接过程
程序的编译和链接的过程
我们在linux下使用gcc编译器直接对程序进行编译,比如使用gcc test.c,然后就会生成一个程序叫做test.out
但是上面的看似简单的过程实际上是经历了四个阶段
预处理,编译,汇编,连接
每个过程都有自己要完成的任务








记住一些操作,ESc对应的是iso,


2.6.1. 预处理
通过预处理生成一个.i的文件,使用的指令是
gcc -E test.c -o test.i
(G)
预处理过程主要处理的是1. 以#开始的预处理指令(保留#pragma)2.删除所有的注释3.添加文件名和行号,具体的过程如下
  • 将所有的#define删除,展开所有的宏定义
  • 处理所有的条件预编译指令,比如#if,#ifdef....
  • 处理所有的#include预编译指令,将所有被包含的文件包含至本文件中来
  • 删除所有的注释,//和/* */等
  • 保留所有的#pragma预处理指令,因为下面还要用到它
2.6.2.编译
gcc -S test.i -o test.s
作用:将预处理后的文件,进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码(这里我们就可以写一个错误的语句来示范一下)
2.6.3. 汇编
gcc -c test.s -o test.o
将汇编代码解释成编译器可以执行的二进制代码
:%!xxd
2.6.4. 链接
gcc -o test.o test
这里我们有一个疑问,不是说上面的汇编已经将程序变成了二进制代码了,为什么还要链接呢,链接是咋链接呢,和谁恋呢,恋啥呢
讲述一下编写程序发展的历史,一开始是程序员是机器码,就是一个一个的纸条上面的01代码,但是这种代码太晦涩难懂了,于是出现了汇编语言,汇编语言出现之后的一个很大的问题就是,代码的数量大大的增加了,这就使得维护代码起来比较复杂,于是人们为了便于维护,又想起把代码分成不同的模块,每个模块负责不同的作用,就比如一个头文件是专门处理图片的,一个头文件是专门处理音频,这样就产生了不同的模块,这些模块之间存在着不同的调用的过程,然后就是要把不同的分开的模块组装起来就是链接的过程。
人们将每个源代码模块独立的编译,然后将编译后的模块按照他们的需求组装起来就是链接的过程。
发给大家一篇PDF《静态库和动态库》




推荐书目:《程序员的自我修养--链接、装载与库》
《C语言深度剖析》




















































更多相关:

  • 最近公司要做一个企业微信的小程序,方便企业内的成员来登录,以便一些公司内的业务,只限于公司内的成员来操作,因为有微信小程序的开发经验,所以先当作微信小程序来开发了!首先来讲一下这个企业微信小程序与微信小程序登录的不同,下面是微信小程序登录的流程:小程序内需要调用wx.login(),获取临时登录凭证code,并回传到开发者服务器,然后...

  • sys.argv[]说白了就是一个从程序外部获取参数的桥梁,这个“外部”很关键,因为我们从外部取得的参数可以是多个,所以获得的是一个列表(list),也就是说sys.argv其实可以看作是一个列表,所以才能用[]提取其中的元素。其第一个元素是程序本身,随后才依次是外部给予的参数。下面我们通过一个极简单的test.py程序的运行结果来说...

  •   标题:创意虾-程序纹理Blender大师班 信息: 什么是程序纹理? 程序纹理将简单的数学转换为无限的真实感着色器,具有无限的多样性和分辨率。 超越看起来像一团像素特写的图像纹理,运用程序纹理的力量,清晰的细节和没有重复的模式。 你是不是在玩节点滑块,得到了一些有趣的结果,但不确定引擎盖下到底发生了什么?掌握了节...

  • gprof用于分析函数调用耗时,可用gprof分析最耗时的函数,以便优化程序。 gcc链接时也一定要加-pg参数,以使程序运行结束后生成gmon.out文件,供gprof分析。 gprof默认不支持多线程程序,默认不支持共享库程序。 gcc 编译程序时添加编译选项-pg 运行程序,程序退出时生成 gmon.outgprof ./...

  • PCL1.9.1并没有支持vs2015版本的exe版本,然后需要下载PCL的源码重新自己CMake编译出vs2015版本的编译的目的:1、得到支持vs2015的版本的PCL1.9.1 前期准备1、下载PCL源码:https://github.com/PointCloudLibrary/pcl2、下载安装版(主要是为...

  • 下载gcc文档,第三章有详细的build options的介绍。 最近我用到2个关键的option 来定位问题,简单介绍一下: 1. -E: 只是进行预编译,不会编译和link。用于检查宏在代码中的展开是否符合预期; 2.--verbose: 开启verbose mode, 用于输出编译整个过程中的详细信息,可帮助查看build...

  • 浅谈GCC预编译头技术 文/jorge ——谨以此文,悼念我等待MinGW编译时逝去的那些时间。 其 实刚开始编程的时候,我是丝毫不重视编译速度之类的问题的,原因很简单,因为那时我用BASICA。后来一直用到C++ Builder,尽管Borland的广告无时无刻不在吹嘘其编译速度,我却从没有对这个问题上心过,因为心里根本没有“...

  • 在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码,我们就称这种编译器支持交叉编译。这个编译过程就叫交叉编译。简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓平台,实际上包含两个概念:体系结构(Architecture)、操作系统(Operating System)。同一个体系结构可以运行...

  • 文章目录前言Makefile 编译流程1. 平台变量/环境变量的初始化。2. 编译需要的源码文件变量初始化。3. include 目录的设置。4. 编译的执行逻辑。问题记录1:可能的打包命令`ar` 失效问题5. 执行具体的编译指令问题记录2: jar 包编译...

  • 本文来自 运维人生 ,作者:fly是个稻草人链接:http://www.ywadmin.com/?id=76误删除linux系统文件了?不用急,本文将给你一个恢复linux文件的方法,让你轻松应对运维中的各风险问题。方法总比问题多~说在前面的话针对日常维护操作,难免会出现文件误删除的操作。大家熟知linux文件系统不同win有回收...

  • 原文来自SecIN社区—作者:WiHat0x00 什么是WebShell渗透测试工作的一个阶段性目标就是获取目标服务器的操作控制权限,于是WebShell便应运而生。Webshell中的WEB就是web服务,shell就是管理攻击者与操作系统之间的交互。Webshell被称为攻击者通过Web服务器端口对Web服务器有一定的操作权限,而...

  • 断电时文件系统发生了什么?硬盘又发生了什么?下一次开机时写到一半的文件在系统层面还在吗?在底层还在吗?更进一步的, 文件系统如何保证事务性, 会不会存在某种极端情况导致例如最后几个bit还没写完, 文件系统却认为它成功了的情况?回答不限任何文件系统,谢谢!下面是「北极」的回复分享断电的一瞬间,很多事情是无法确定的:1. 你无法确定...

  • 接到项目需求。需要搭建一个页面进行交互,慢慢来b (2).jpg使用python django框架进行页面的搭建在项目文件下打开窗口,输入命令;django-admin startproject helloword#在文件helloword/helloword/创建view.py在view.py文件中输入以代码from django....

  • 常见的错误集合解决方案(一)No.1提示错误'Microsoft.VC90.CRT,version="9.0.21022.8"把Microsoft.NET Framework 3.5.1下面的全部勾选上。No.2解决Qt Designer设计的图标但是VS生成不显示问题描述:在Qt designer中为菜单栏和工具栏设计的图标,但是...