当前位置: 首页 > news >正文

C语言程序的编译和链接

一、程序的翻译环境

翻译环境:组成程序的每个源文件通过编译器编译成目标文件,所有的目标文件在由连接器捆绑在一起形成一个单一而完整的可执行程序。同时,链接器也会引入标准c函数库中任何被该程序所有到的函数,而且他可以搜索程序员个人的程序库将其需要的函数也链接到程序中。

程序编译连接过程:程序的编译和和链接包括程序的预处理、编译、汇编和链接4个步骤,每个步骤都由其具体的任务。

1.预处理

预处理主要有展开头文件、宏替换、条件编译、去掉注释四个任务,经过这4个步骤最终生成一个' .i '文件(Linux环境下,不同环境会有所不同)。

展开头文件:在程序中,使用到一些库函数或者其他文件中的函数时都要包含其所在文件。程序会在预处理阶段将这些头文件中的函数展开在该文件前,当函数执行到这些函数时会直接在展开的这些文件中找有没有所需要的的函数,如果没有可能就会报错。

宏替换:宏是一种替换机制,因此在预处理阶段,会将定义的宏按照定义进行替换。

条件编译:条件编译是指预处理器根据条件编译指令,有条件地选择源程序代码中的一部分代码作为输出,送给编译器进行编译。主要是为了有选择性地执行相应操作,防止宏替换内容(如文件等)的重复包含。

去掉注释:预编译过程中,预编译器会对程序中的注释进行删除。

2.编译

编译过程主要任务就是检查语法、生成汇编代码(生成“ . s”文件)。也就是说,我们写的程序如果有语法错误,在编译阶段就会被检查出来,如果不是语法错误编译阶段是检查 不出来的。

3.汇编:将汇编代码转成二进制机器码(.o文件),这里的汇编和编译过程中的汇编是不一样的,这里的汇编是指生成二进制机器码,而上边的汇编是指生成汇编指令。

4.链接:将目标文件链接到一起,生成可执行文件(.exe文件)。

二、程序的运行环境

程序执行过程:

1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。

2. 程序的执行便开始。接着便调用main函数。

3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同 时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。

4. 终止程序。正常终止main函数;也有可能是意外终止。

 三、预处理详解

1.预定义符号(语言内置好的)

__FILE__      //进行编译的源文件

__LINE__     //文件当前的行号

__DATE__    //文件被编译的日期

__TIME__    //文件被编译的时间

__STDC__    //如果编译器遵循ANSI C,其值为1,否则未定义

使用举例:

int main()
{
	printf("当前文件的路径:%s\n当前代码的行号:%d\n", __FILE__, __LINE__);
	printf("文件编译日期:%s\n",__DATE__);
	printf("文件编译时间:%s\n", __TIME__);
	return 0;
}

 运行结果:

2.#define

#define定义标志符

语法:#define  name  stuff

例子:

#define  MAX  10000     //定义一个宏常量,用10000替换

#define   REG  register   //为关键字定义一个简短的名字

//如果定义的stuff过长,可以分成几行写,除了最后一行其他行的结尾都加上\(续行符)

#define DEBUG_PRINT printf("file:%s\tline:%d\t \

                         date:%s\ttime:%s\n" ,\

                         __FILE__,__LINE__ ,       \

                         __DATE__,__TIME__ )

注意:宏定义常量的时候,不能加;号。例如: #define  MAX  10000;后边的;不能加,因为宏为替换机制,如果加上分号就会出现错误。例如:

#define MAX 1000;
int mian()
{
    int num[MAX];//错误,

    int a = MAX //正确,注意这条语句没有写;,而是直接利用宏替换的;
    return 0;
}

#define宏定义

#defifine 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(defifine macro)。

分析下面程序的运行结果:

PROGRAM ONE

#define add(a,b) a+b

printf("%d\n",add(2,3));
//毫无疑问,这个运行结果就是2+3=5

printf("%d\n",add(2,3)*5);
//这里,2+3*5=17

PROGRAM TWO

#define add(a,b) (a+b)

printf("%d\n",add(2,3));
//(2+3)=5

printf("%d\n", add(2 , 3)*5);
//(2+3)*5=25

PROGRAM TREE

#define mul(a,b) a*b

printf("%d\n",add(2+3,5));
//2+3*5=17

#define mul(a,b) (a)*(b)

printf("%d\n",add(2+3,5));
//(2+3)*(5)=25

#define替换规则

在程序中扩展#defifine定义符号和宏时,需要涉及几个步骤。

1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#defifine定义的符号。如果是,它们首先被替换。

2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。

3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#defifine定义的符号。如果是,就重复上述处理过程。

注意:

1. 宏参数和#defifine 定义中可以出现其他#defifine定义的变量。但是对于宏,不能出现递归。

2. 当预处理器搜索#defifine定义的符号的时候,字符串常量的内容并不被搜索。

相关文章:

  • nowcoder---统计子串个数(C语言)
  • LeetCode---搜索二维矩阵(c语言)
  • C语言编程过程中与到的问题(不定时更新)
  • 计算机中加减乘除的实现
  • Linux基本指令+使用举例、权限的认识和相关指令、Linux添加删除用户、shell的理解(超详细)
  • Linux连接网络、修改账户密码
  • LeetCode---删除排序数组中的重复项(C语言)
  • LeetCode---合并两个有序数组
  • leetcode---返回链表的中间节点
  • 学生成绩管理系统---数据结构、C语言课程设计
  • 数据结构课程设计---学生成绩管理系统
  • leetcode---环形链表(快慢指针证明)
  • leetcode---环形链表II
  • 剑指offer---复制带随机值的链表
  • Linux---进程概念
  • 【Leetcode】101. 对称二叉树
  • [iOS]Core Data浅析一 -- 启用Core Data
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • echarts花样作死的坑
  • HomeBrew常规使用教程
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • Laravel Mix运行时关于es2015报错解决方案
  • mysql 数据库四种事务隔离级别
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • vue--为什么data属性必须是一个函数
  • Xmanager 远程桌面 CentOS 7
  • 从0到1:PostCSS 插件开发最佳实践
  • 搭建gitbook 和 访问权限认证
  • 实习面试笔记
  • 使用 QuickBI 搭建酷炫可视化分析
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 小试R空间处理新库sf
  • 优秀架构师必须掌握的架构思维
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • # 飞书APP集成平台-数字化落地
  • #控制台大学课堂点名问题_课堂随机点名
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (2)STL算法之元素计数
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (七)Java对象在Hibernate持久化层的状态
  • (四)Linux Shell编程——输入输出重定向
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转) Face-Resources
  • (转)Linq学习笔记
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件