程序的编译、链接

目录

前言:

前置知识回顾

宏定义常量

宏定义语句

宏定义函数

条件编译

应用场景

编译过程概览

预编译阶段

编译阶段

 汇编阶段

 链接阶段


前言:

在ANSI C的任何一种实现中,存在两种不同的环境,第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令;第2种是执行环境,它用于实际执行代码,将磁盘中的可执行文件装载到内存中,CPU才能通过总线读取内存中的指令,才能真正执行程序;本文重点阐述程序的翻译坏境;

前置知识回顾

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro);
命名习惯: 宏名全部大写
//宏的声明:
  #define name( parament-list ) stuff
//其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中;
//注意:参数列表的左括号必须和宏名name紧邻;
//如果宏名与参数列表之间有任何空白存在,参数列表就会被解释为stuff的一部分;

宏定义常量

# define ROW 10            //宏定义整型常量
# define PI  3.14          //宏定义浮点型常量
# define STR "hello world" //宏定义字符串
int main()
{
	printf("%d %f %s\n", ROW, PI, STR);
	return 0;
}
运行结果:

宏定义语句

# define PRINTF printf("Hello Linux!\n");
int main()
{
	int i = 10;
	PRINTF;
	return 0;
}

运行结果:

宏定义函数

宏可以接收参数且不用指定参数类型;

# define ADD(x,y) ((x)+(y))
int main()
{
	int m = 10;
	int n = 10;
	float d1 = 4.5;
	float d2 = 5.5;
	printf("%d\n", ADD(m,n));
	printf("%f\n", ADD(d1, d2));
	return 0;
}

运行结果:

条件编译

编译程序时使用条件编译指令选择性的将一条语句/一组语句编译或者放弃;
//常见的条件编译指令
#if:    如果条件为真,则执行相应的操作;
#elif:   类似于else if的用法,当前面条件为假,再判断该条件是否为真,如果是真,则执行相应操作;
#else:   如果前面所有条件均为假,则执行相应操作;
#ifdef:  如果该宏已定义,则执行相应操作;
#ifndef: 如果该宏没有定义,则执行相应操作;
#endif : 结束对应的条件编译指令(不能省略);

应用场景

# define VERSION1 1
//# define VERSION2 2
int main()
{
#ifdef VERSION1
	printf("Hello Version1.0\n");
#elif VERSION2
	printf("Hello Version2.0\n")
#else 
	printf("Hello Free Version");
#endif
	return 0;
}

运行结果:

//# define VERSION1 1
//# define VERSION2 2
int main()
{
#ifdef VERSION1
	printf("Hello Version1.0\n");
#elif VERSION2
	printf("Hello Version2.0\n")
#else 
	printf("Hello Free Version\n");
#endif
	return 0;
}

运行结果:

编译过程概览

将一个.c文件翻译为可执行文件,需要经过预编译(prepressing) 、编译(compliation)、汇编(assernbly)、链接(linking)四个阶段;

预编译阶段

  • 头文件展开
  • 去掉注释
  • 宏替换
  • 条件编译
 //vim编辑器编写test.c文件
 # include <stdio.h>
 # define M 100
 int main()
   {
    printf("%d\n",M);                                                                                                                           
    //printf("hello Linux!\n");
    //printf("hello Linux!\n");
    //printf("hello Linux!\n");
    printf("hello world!\n"); 
    return 0;
   }

Linux环境使用选项 gcc -E test.c -o test.i

此条语句的含义为从现在开始进行程序的翻译过程,当预处理结束时,停止程序的翻译过程;

上图生成test.i文件,使用vim编辑器打开test.i文件;

注释被删除掉,宏定义的M被替换为100,使用选项 vim /usr/include/stdio.h 打开c标准库对比发现头文件被替换;

使用vim编辑器编写code.c代码,code.c代码使用条件编译指令;

//vim编辑器编写code.c代码
# define VERSION1 1
//# define VERSION2 2
int main()
{
#ifdef VERSION1
	printf("Hello Version1.0\n");
#elif VERSION2
	printf("Hello Version2.0\n")
#else 
	printf("Hello Free Version\n");
#endif
	return 0;
}

编译阶段

1. 词法分析:词法分析器处理test.i文件,将字符串切割成一个个记号(mark)

      例如:sum=a+b;会产生五个记号:"sum" "=" "a" "+" "b"
2. 语法分析:语法分析器将产生的记号组织成一个个表达式,以表达式为节点,生成一颗语法树
3. 语义分析:语义分析器处理声明以及数据类型、给语法树的节点赋予数据类型
4. 中间代码:根据语法树生成中间代码,以上的步骤是硬件平台无关的,而中间代码之后的处理则需要根据程序运行的硬件平台来决定;
5. 代码生成器:代码生成器将中间代码转换成对应硬件平台的汇编代码test.s

Linux环境使用选项 gcc -S test.c -o test.s

此条语句的含义为从现在开始进行程序的翻译过程,当编译结束时,停止程序的翻译过程;

 汇编阶段

汇编器:汇编器根据 汇编指令与机器指令的对照表 将汇编代码翻译成机器指令,生成目标文件test.o;

目标文件由若干个段(section)组成,每个段中存放不同的内容;

目标文件中的基本段类型:文件头、代码段、数据段、bss段、常量段、段表、符号表、重定位表;

文件头:文件头位于目标文件开始位置,它定义了elf魔数,目标文件的属性、运行的软硬件平台、程序入口地址、段表的位置及长度、段的数量;

代码段:存放  机器指令

数据段:   存放 已经初始化的全局变量以及静态变量

常量段:存放  字符串常量以及被const修饰的变量

bss段: 存放  未初始化的全局变量以及静态变量所占用的内存大小

段表:    记录了目标文件中所有段的地址以及属性(读写or可执行)等信息;

符号表:记录与程序相关的所有符号(如变量、函数名),变量或者函数所对应的地址和属性

重定位表:重定位表用于指示需要进行重定位的指令或数据,记录了位置信息、长度以及对应的符号引用;

Linux环境使用选项 gcc -c test.c -o test.s

此条语句的含义为从现在开始进行程序的翻译过程,当汇编结束时,停止程序的翻译过程;

 链接阶段

链接器:合并输入的.o文件、确定符号内存地址、进行符号重定位,输出可执行文件;

 Linux环境使用选项 gcc test.c -o test.exe

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/280204.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

go module本地包导入

go module本地包导入 本文目录 go module本地包导入启用go mod主项目工作目录本地module目录发布和使用模块 golang 1.11之后加入了go mod来替代GOPATH 官方文档参考&#xff1a;https://golang.google.cn/doc/tutorial/call-module-code 启用go mod 开启 Go modules # 临时开…

一文带你了解大模型的RAG(检索增强生成) | 概念理论介绍+ 代码实操(含源码)

针对大型语言模型效果不好的问题&#xff0c;之前人们主要关注大模型再训练、大模型微调、大模型的Prompt增强&#xff0c;但对于专有、快速更新的数据却并没有较好的解决方法&#xff0c;为此检索增强生成&#xff08;RAG&#xff09;的出现&#xff0c;弥合了LLM常识和专有数…

数据治理:释放数据价值的关键

随着数字化时代的到来&#xff0c;数据已成为组织和企业最重要的资产之一。然而&#xff0c;数据的快速增长和复杂性也给数据管理带来了巨大的挑战。为了确保数据的质量、安全性和合规性&#xff0c;数据治理已成为组织和企业必须面对的重要问题。数据治理是数据要素市场建设的…

自动驾驶学习笔记(二十三)——车辆控制模型

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo开放平台9.0专项技术公开课》免费报名—>传送门 文章目录 前言 运动学模型 动力学模型 总结…

Java进阶(第八期): Java中递归的的使用和递归解决一些算法问题 Java中的异常机制、异常的处理逻辑 自定义异常

文章目录 一、递归1.1 递归的介绍1.2 递归的简单练习1.3 图解递归执行流程&#xff1a;1.4 使用递归完成悲波那契数列1.5 猴子吃桃子问题 二、异常三 、异常的处理逻辑3.1 try catch 捕获异常3.2 throws抛出异常 四、自定义异常 Java进阶&#xff08;第八期&#xff09; 一、递…

如何安装、配置、启动及访问Nacos

准备 JDK 17.0&#xff1a;https://www.bilibili.com/video/BV1ig4y1k7Bq?p2 MySQL 8.0&#xff1a;https://www.bilibili.com/video/BV1QU4y117Vn Navicat Premium&#xff1a;https://www.bilibili.com/video/BV1F94y1A7nC 1、安装Nacos a、地址 网址&#xff1a;http…

ElasticSearch 架构设计

介绍 ElasticSearchMySQLIndexTableDocumentRowFieldColumnMappingSchemaQuery DSLSQLaggregationsgroup by&#xff0c;avg&#xff0c;sumcardinality去重 distinctreindex数据迁移 ElasticSearch 中的一个索引由一个或多个分片组成 每个分片包含多个 segment&#xff08;分…

用 Node.js 写一个爬虫

自己设计一个网站&#xff0c;然后去爬取别人家页面的数据来做一个自己的网站。哈哈哈&#xff0c;如果自己写着玩可能没啥事&#xff0c;但如果用这个网站来获利&#xff0c;你可能就要被寄律师函了&#xff0c;毕竟这有点‘刑’。这篇文章呢&#xff0c;就带大家爬取豆瓣TOP2…

HDMI2.1输入转4Port MIPI/LVDS输出,嵌入式SPI闪存固件存储,VR和AR应用首选国产芯片方案-LT6911GXC

描述 LT6911GXC是一款高性能的HDMI2.1到MIPI或LVDS芯片&#xff0c;用于VR/显示应用。 HDCP RX作为HDCP中继器的上游&#xff0c;可配合其他芯片的HDCPTX实现中继器功能。 对于HDMI2.1输入&#xff0c;LT6911GXC可以配置为3/4通道。自适应均衡使其适合于长电缆应用&#xff0c;…

申请虚拟VISA卡Fomepay教程

fomepay 用下面的注册链接直达 https://gpt.fomepay.com/#/pages/login/index?dS21BA1 或者扫描下面图片的二维码直达注册 注册后尽量随用随充值不建议放大量现金在里面。

【论文解读】用于概念标定的逻辑强化大模型LEFT(NeurIPS 2023)

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://arxiv.org/abs/2310.16035 开源代码&#xff1a;https://github.com/joyhsu0504/LEFT 摘要&#xff1a; VisProg 和 ViperGPT 等最新研究成果巧妙地组成了视觉推理的基础模型-…

vscode配置python环境,步骤以及 chatgpt和csdn AI创作助手回答对比

1解决步骤 参考地址 解决步骤 vscode 安装 python插件&#xff0c;并重启vscode&#xff0c;前提是电脑已经配置了python环境&#xff0c;我的电脑已经安装了anaconda 也有python3 新建文件夹 pythonTst &#xff0c;vscode中菜单栏 File --Add folder toWordSpace — 弹出框…

PNG免抠素材库,免费下载,可商用~

本期分享5个高质量PNG素材网站&#xff0c;让你在工作中大大提高效率&#xff0c;节省更多的时间&#xff0c;赶紧收藏起来吧~ 1、菜鸟图库 https://www.sucai999.com/searchlist/66008----all-0-1.html?vNTYxMjky 网站主要分享设计素材为主。像平面海报、免抠元素、背景图片…

常见推断方法一览:极大似然估计、最大后验估计、期望最大化、贝叶斯推断、马尔科夫链蒙特卡洛方法、变分推断

常见推断方法一览 推断方法区别频率派极大似然估计 MLE最大后验估计 MAP期望最大化 EM 贝叶斯推断 Bayesian马尔科夫链蒙特卡洛方法 MCMC变分推断 VI 推断方法区别 极大似然估计 (Maximum Likelihood Estimation, MLE): 解释: 假设你有一堆骰子&#xff0c;你投掷它们很多次&am…

行车记录仪变清晰,变高清的办法一定要收藏

有时候我们会发现行车记录仪拍摄的视频不够清晰&#xff0c;特别是出现事故需要视频为证的时候&#xff0c;如果视频太模糊&#xff0c;很难获得交警的支持&#xff0c;那么如何让行车记录仪拍摄的视频变得更加清晰呢&#xff1f; 小编给大家分享几个办法&#xff0c;建议收藏…

Getway介绍和使用

Getway 入门简介 网关搭建步骤&#xff1a; 创建项目&#xff0c;引入nacos服务发现和gateway依赖 配置application.yml&#xff0c;包括服务基本信息、nacos地址、路由 路由配置包括&#xff1a; 路由id&#xff1a;路由的唯一标示 路由目标&#xff08;uri&#xff09;…

openGauss学习笔记-180 openGauss 数据库运维-升级-升级前必读

文章目录 openGauss学习笔记-180 openGauss 数据库运维-升级-升级前必读180.1 升级方案180.2 升级前的版本要求180.3 升级影响和升级约束 openGauss学习笔记-180 openGauss 数据库运维-升级-升级前必读 180.1 升级方案 本节为指导用户选择升级方式。 用户根据openGauss提供的…

按摩上门预约小程序源码系统 开发组合:PHP+MySQL 附带完整的搭建教程

现代生活节奏的加快&#xff0c;人们越来越注重健康与放松。按摩作为传统的舒缓方式&#xff0c;市场需求逐年上升。然而&#xff0c;传统的按摩服务预约方式较为繁琐&#xff0c;用户需拨打热线电话或前往实体店进行预约&#xff0c;这无疑增加了用户的操作成本。因此&#xf…

redhat 8 安装openstack

redhat 8 安装openstack 1、安装文档2、redhat 8 安装openstack3、使用openstack 1、安装文档 openstack官方安装文档 https://docs.openstack.org/install-guide/ 2、redhat 8 安装openstack 3、使用openstack

人工智能——移动摄影技术

目录 封面 1 .移动计算摄影简介 2.手机相机的硬件限制 2.1 传感器尺寸和镜头孔径 2.2 噪声和动态范围 2.3 景深 2.4 变焦 2.5 色彩欠采样 3 .相机图像处理流水线 3.1 相机传感器 3.2 相机流水线 5.拓展 1 .移动计算摄影简介 现代数字摄影的进度始终伴随着图像传感器…
最新文章