程序的编译、链接

目录

前言:

前置知识回顾

宏定义常量

宏定义语句

宏定义函数

条件编译

应用场景

编译过程概览

预编译阶段

编译阶段

 汇编阶段

 链接阶段


前言:

在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 VERSION1printf("Hello Version1.0\n");
#elif VERSION2printf("Hello Version2.0\n")
#else printf("Hello Free Version");
#endifreturn 0;
}

运行结果:

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

运行结果:

编译过程概览

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

预编译阶段

  • 头文件展开
  • 去掉注释
  • 宏替换
  • 条件编译
 //vim编辑器编写test.c文件# include <stdio.h># define M 100int 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 VERSION1printf("Hello Version1.0\n");
#elif VERSION2printf("Hello Version2.0\n")
#else printf("Hello Free Version\n");
#endifreturn 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.hqwc.cn/news/309440.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件工程导论——(为什么要学习软件工程?软件工程能学到什么?如何学习软件工程?)

导论&#xff08;引言&#xff09;&#xff1a; 1.为什么要学习软件工程&#xff1f; 软件工程知识并不只是项目管理可以用&#xff0c;同样适用于开发岗。比如开发也要做需求分析和架构设计&#xff0c;也要做计划。学习软件工程后也可以帮助开发人员更好的理解软件项目的整个…

pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1,因为在此系统上禁止运行脚本。

一、问题描述 在VS Code中运行Terminal中运行pnpm install&#xff08;npm或yarn也类似&#xff09;报错&#xff1a; S D:\workspace\xxx\xxx> pnpm install pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息…

DES加密算法优缺点大揭秘:为何它逐渐被取代?

一、引言 DES&#xff08;Data Encryption Standard&#xff09;加密算法作为一种历史悠久的对称加密算法&#xff0c;自1972年由美国国家标准局&#xff08;NBS&#xff09;发布以来&#xff0c;广泛应用于各种数据安全场景。本文将从算法原理、优缺点及替代方案等方面&#…

eve环境虚拟机和电脑如何传送文件

一.桥接 &#xff08;实现电脑和虚拟机在同一网段&#xff09; 虚拟机上网盘设置 二.属性---文件共享设置 1打开属性&#xff0c;点击共享 2.添加共享人为全部人&#xff0c;并修改权限为读写模式 3.点击高级共享&#xff0c;选定此文件夹 4.点击网络和共享中心&#xff0c;划…

Mixtral 8*7B + Excel + Python 超强组合玩转数据分析

Mixtral 8*7B Excel Python 超强组合玩转数据分析 0. 背景1. 使用 Mixtral 8*7B pandas 实现数据导入和导出1.1 使用 Mixtral 8*7B pandas 导入 Excel 文件中的数据1.2 使用 Mixtral 8*7B pandas 导出 Excel 文件中的数据 2. 使用 Mixtral 8*7B pandas 实现单个文件数据的…

Nginx快速入门:nginx实现正向代理|反向代理和正向代理的区别(八)

0. 引言 我们之前讲解的一直是nginx的反向代理配置&#xff0c;关于正向代理的实现一直没有涉及&#xff0c;但在实际生产中正向代理也有非常广泛的应用场景&#xff0c;因此&#xff0c;今天我们将针对正向代理来深入学习。 1. 相关概念 1.1 什么是反向代理 所谓反向代理&…

如何恢复 iPhone 上永久删除的照片?

2007年&#xff0c;苹果公司推出了一款惊天动地的智能手机&#xff0c;也就是后来的iPhone。你会惊讶地发现&#xff0c;迄今为止&#xff0c;苹果公司已经售出了 7 亿部 iPhone 设备。根据最新一项调查数据&#xff0c;智能手机利润的 95% 都进了苹果公司的腰包。 如此受欢迎…

分糖果C语言

分析&#xff1a;我们假设有n个小朋友&#xff0c;我们可以以每一个小朋友作为开头传递一次&#xff0c;我们将每一种情况栓出来&#xff0c;在判断哪种代价最小&#xff0c;就输出哪种 例子&#xff1a;下面这种情况是把1当成开头&#xff0c;结果是6 把2换成第一个&#xf…

关于java循环结构for

关于java循环结构for 在上一篇文章中&#xff0c;我们了解到了while和do…while的结构以及用法&#xff0c;这篇文章我们主要学习一下最常用的循环结构&#xff0c;for结构&#x1f600;&#xff0c;这个结构理解起来相对while结构会难一些&#xff0c;本篇文章内容会很多&…

苹果CMS超级播放器专业版无授权全开源,附带安装教程

源码介绍 超级播放器专业版v1.0.8&#xff0c;内置六大主流播放器&#xff0c;支持各种格式的视频播放&#xff0c;支持主要功能在每一个播放器内核中都相同效果。 搭建教程 1.不兼容IE浏览器 2.php版本推荐7.4 支持7.1~7.4 3.框架引入不支持同时引入多个播放器 json对接教…

大数据毕业设计:旅游景点数据爬虫大屏实时监控系统✅

毕业设计&#xff1a;2023-2024年计算机专业毕业设计选题汇总&#xff08;建议收藏&#xff09; 毕业设计&#xff1a;2023-2024年最新最全计算机专业毕设选题推荐汇总 &#x1f345;感兴趣的可以先收藏起来&#xff0c;点赞、关注不迷路&#xff0c;大家在毕设选题&#xff…

SpringBoot整合Canal

一 linux docker compose版本 1.第一步&#xff1a;基础环境 &#xff08;1&#xff09;第1步&#xff1a;安装jak、maven、git、nodejs、npm yum install maven mvn -v 安装maven时会帮安装jdkyum install git git --version 2.27.0yum in…