C语言 — 编译和链接

目录

  • 1.程序从源文件到结果输出的执行过程
  • 2.预处理
  • 3.编译
    • 3.1 词法分析
    • 3.2 语法分析
    • 3.3 语义分析
    • 3.4 生成test.s文件
  • 4.汇编
  • 5.链接
  • 6.运行

1.程序从源文件到结果输出的执行过程

在这里插入图片描述

2.预处理

预处理阶段的执行操作:

预处理阶段会将#define定义的常量或宏进行替换,经过预处理后的文件#define的语句就不存在;

预处理阶段会将注释进行删除,并对行号进行标识;

预处理阶段会处理#include包含的头文件,将其内容进行插入,此过程是可以递归进行的,因为包含的头文件中可能包含其它头文件;

预处理阶段会处理#if #endif #elif #ifdef #else的条件编译指令,对表达式进行判断处理;

预处理阶段会保留所有#pragma指令。

以下为简单例子展示,创建三个文件:Add.h,Add.c,test.c

//Add.h文件
#pragma once//防止头文件重复包含//类似效果
//#ifndef C //判断是否没有定义符号M
//
//#define C //定义符号C
//
//#include<stdio.h>//重复包含多次
//#include<stdio.h>
//#include<stdio.h>
//
//#endif//结束#ifenf条件判断指令#include<stdio.h>#ifndef M //判断是否没有定义符号M#define M 100//定义符号M#endif//结束#ifenf条件判断指令#define N 200int Add(int x, int y);//函数声明
//Add.c文件
#include"Add.h"//包含头文件
//函数定义
int Add(int x, int y)
{return (x + y);
}
//test.c文件
#include "Add.h"//包含头文件int main()
{//输出两个数的和printf("%d", Add(M, N));return 0;
}

将以上代码在VS环境下输入后Ctrl + S保存,打开文件保存的位置,点击输入cmd后回车,打开cmd.

在这里插入图片描述
在这里插入图片描述
打开cmd后需要输入指令,将源文件转变为.i为后缀的中间文件

gcc -E test.c -o  test.i

在这里插入图片描述
gcc是一个编译器,需要下载相应的插件才可以使用,具体流程可以参考以下文章:

https://blog.csdn.net/qq_36318563/article/details/140336690

以上文章可能介绍的网站打不开,可以使用以下链接:MinGW下载

在这里插入图片描述

输入以上指令后会生成一个test.i的文件,可以在VS2022中打开观察

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因为头文件的插入有400多行代码,以上就不做过多的展示,最后可以看到处理后的#define定义的常量和条件编译指令进行了处理和替换,并将注释删除。

3.编译

编译阶段会进行词法分析,语法分析和语义分析及优化,以下面例子为参考

  arr[n] = i + 1;

3.1 词法分析

词法分析阶段会将语句的标识符,操作符,数字进行标记,以上语句可以得到以下标记

在这里插入图片描述

3.2 语法分析

语法分析阶段会根据标记生成语法树,语法树是根据表达式为节点的数。
在这里插入图片描述

3.3 语义分析

语义分析阶段是对语法层面的意思进行转换,包括声明,类型的匹配和转换等,此时会报告错误信息,经过语义分析后的语法树。

在这里插入图片描述

3.4 生成test.s文件

对test.i的中间文件通过以下指令编译生成test.s的文件

gcc -S test.i -o test.s

在这里插入图片描述

在这里插入图片描述
将生成的test.s文件在VS2022中打开,文件内容是汇编代码。

	.file	"test.c".text.globl	_Add.def	_Add;	.scl	2;	.type	32;	.endef
_Add:
LFB10:.cfi_startprocpushl	%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl	%esp, %ebp.cfi_def_cfa_register 5movl	8(%ebp), %edxmovl	12(%ebp), %eaxaddl	%edx, %eaxpopl	%ebp.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc
LFE10:.def	___main;	.scl	2;	.type	32;	.endef.section .rdata,"dr"
LC0:.ascii "%d\0".text.globl	_main.def	_main;	.scl	2;	.type	32;	.endef
_main:
LFB11:.cfi_startprocpushl	%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl	%esp, %ebp.cfi_def_cfa_register 5andl	$-16, %espsubl	$16, %espcall	___mainmovl	$200, 4(%esp)movl	$100, (%esp)call	_Addmovl	%eax, 4(%esp)movl	$LC0, (%esp)call	_printfmovl	$0, %eaxleave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc
LFE11:.ident	"GCC: (MinGW.org GCC-6.3.0-1) 6.3.0".def	_printf;	.scl	2;	.type	32;	.endef

4.汇编

汇编过程是将汇编代码转换为二进制代码,每一条汇编语句都代表一条指令,将汇编语句与机器语句通过对照表转换,不做任何优化,通过以下指令将test.s的文件转换为test.o的目标文件。

gcc -c test.s -o test.o

在这里插入图片描述

在这里插入图片描述

打开test.o的文件,可以观察到都是二进制的编码

L?.textH? 0`.data@0?bss€0?rdataL@0@/4$P@0@/15Xt?@0@U夊婾婨衇肬夊冧饍?枨D$惹$d柩塂$?$韪擅悙%dGCC: (MinGW.org GCC-6.3.0-1) 6.3.0zR|?
A?B
I?<9A?B
u?6; @.file?gtest.c_Add _main.textF.data.bss.rdata#$X___main _printf ..rdata$zzz.eh_frame.rdata$zzz.eh_frame

5.链接

链接过程主要处理地址和空间分配,符号决议和符号重定位等操作,最后通过链接库链接生成可执行程序。

例子:

add.c文件int n = 100;//全局变量int Add(int x,int y)
{return x + y;
}
test.c文件extern int n;//声明外部符号
extern int Add(int ,int)//声明外部符号int main()
{int r = Add(2,3)printf("r = %d",r);printf("n = %d",n);return 0;
}

地址和空间分配在链接过程,每一个.o为后缀的文件生成后都会有对应的符号表,对于add.o文件和test.o文件如下:一般符号标记录的是函数名和全局变量或静态变量。

在这里插入图片描述

因为test.c文件中的n和Add是外部符号,在链接前并不确定这些外部符号的具体地址,系统会随机分配一个虚假的地址;有了各自文件的符号表就可以进行符号的决议和重定位。

在这里插入图片描述

通过以上过程确定最终的符号表,再通过链接库的链接就可以生成可执行程序,可以通过以下的指令

//因为需要test.o和Add.o文件进行链接,此时有了test.o文件,再生成一个Add.o的文件gcc -c Add.c -o Add.o

在这里插入图片描述
在这里插入图片描述

有了test.o和Add.o文件就可以通过链接库链接生成可执行程序,使用以下指令

//生成一个test.exe的可执行程序
gcc test.o Add.o -o test

在这里插入图片描述
在这里插入图片描述

6.运行

运行过程需要在运行时环境下进行,可执行程序的运行必须先将程序植入内存,在操作系统中,一般由操作系统完成;调用函数时会开辟运行时堆栈(即函数栈帧的创建),一般函数是从main函数进入,在开辟过程会保存局部变量和函数的地址,全局或静态变量会存储于静态区,直到函数销毁而销毁,最后随main函数的结束而终止程序 ,并输出结果。

对应可执行程序在cmd指令中直接输入文件名后回车即可输出结果:

test.exe

在这里插入图片描述

以上内容只是编译和链接的大概介绍,如果对编译链接想要进一步的了解,可以参考以下书籍:

《程序员的自我修养》

其它推荐书籍:高质量c/c++编程

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

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

相关文章

传统业务对接AI-AI编程框架-Rasa的业务应用实战(5)--Rasa成型可用 rasa服务化部署及识别意图后的决策及行为

此篇接续上一篇 传统业务对接AI-AI编程框架-Rasa的业务应用实战&#xff08;4&#xff09;--Rasa成型可用 针对业务配置rasa并训练和部署 上一篇我们已经让Rasa准确识别了我们自然语言指令的开票和查询发票的意图和实体。 # 开具发票场景 用户输入&#xff1a;开具一张1000元…

MajicTryOn(基于wanvideo的虚拟试穿项目)

网络结构 Attention模块详解 左边服装通过qwen2.5-VL-7B来生成详细的服装描述&#xff1b;线条提取器产生相应的线条map&#xff1b;garment和line map通过vae转换为潜在空间特征&#xff0c;然后分别经过patchfier,最后通过zero proj得到Garment Tokens和Line Tokens;右边是di…

JAVA-什么是JDK?

1.JDK 的定义 JDK&#xff08;Java Development Kit&#xff09;是 Java 开发工具包&#xff0c;是 Oracle 官方提供的用于开发、编译和运行 Java 应用程序的核心工具集。它包含了编写 Java 程序所需的编译器、调试工具、库文件以及运行时环境&#xff08;JRE&#xff09;。 2…

Palo Alto Networks Expedition存在命令注入漏洞(CVE-2025-0107)

免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规,并取得目标系统的明确授权。 对于因不当使用本文信息而造成的任何直…

分布式光纤传感(DAS)技术应用解析:从原理到落地场景

近年来&#xff0c;分布式光纤传感&#xff08;Distributed Acoustic Sensing&#xff0c;DAS&#xff09;技术正悄然改变着众多传统行业的感知方式。它将普通的通信光缆转化为一个长距离、连续分布的“听觉传感器”&#xff0c;对振动、声音等信号实现高精度、高灵敏度的监测。…

独家首发!低照度环境下YOLOv8的增强方案——从理论到TensorRT部署

文章目录 引言一、低照度图像增强技术现状1.1 传统低照度增强方法局限性1.2 深度学习-based方法进展 二、Retinexformer网络原理2.1 Retinex理论回顾2.2 Retinexformer创新架构2.2.1 光照感知Transformer2.2.2 多尺度Retinex分解2.2.3 自适应特征融合 三、YOLOv8-Retinexformer…

96. 2017年蓝桥杯省赛 - Excel地址(困难)- 进制转换

96. Excel地址&#xff08;进制转换&#xff09; 1. 2017年蓝桥杯省赛 - Excel地址&#xff08;困难&#xff09; 标签&#xff1a;2017 省赛 1.1 题目描述 Excel 单元格的地址表示很有趣&#xff0c;它使用字母来表示列号。 比如&#xff0c; A 表示第 1 列&#xff0c;…

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…

Druid连接池实现自定义数据库密码加解密功能详解

Druid连接池实现自定义数据库密码加解密功能详解 在企业级应用开发中&#xff0c;数据库密码的明文存储是一个显著的安全隐患。Druid作为阿里巴巴开源的高性能数据库连接池组件&#xff0c;提供了灵活的密码加密与解密功能&#xff0c;允许开发者通过自定义逻辑实现数据库密码…

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…

Java并发编程实战 Day 12:阻塞队列与线程协作

【Java并发编程实战 Day 12】阻塞队列与线程协作 开篇 欢迎来到“Java并发编程实战”系列的第12天&#xff01;今天我们将深入探讨阻塞队列&#xff08;BlockingQueue&#xff09;及其在线程协作中的应用。阻塞队列是Java并发编程中一个非常重要的工具&#xff0c;它不仅简化…

Linux 前后端项目问题排查命令手册

一、系统资源监控类命令​ 1. CPU 资源排查​ top - 动态实时监控进程​ top [选项] 常用选项: -d 2 # 每2秒刷新一次 -H # 显示线程信息 -p 1234 # 仅监控PID为1234的进程 输出解读:​ %Cpu(s):总 CPU 使用率,用户态 + 内核态​KiB Mem:内…

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…

vue3前端实现导出Excel功能

前端实现导出功能可以使用一些插件 我使用的是xlsx库 1.首先我们需要在vue3的项目中安装xlsx库。可以使用npm 或者 pnpm来进行安装 npm install xlsx或者 pnpm install xlsx2.在vue组件中引入xlsx库 import * as XLSX from xlsx;3.定义导出实例方法 const exportExcel () …

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…

Redis配合唯一序列号实现接口幂等性方案

1.原理 可以在客户端每次请求服务端的时候&#xff0c;客户端请求中携带一个短时间内唯一不重复的序列号来确保其唯一性&#xff0c;这个序列号常见的几种形式有&#xff1a;基于时间戳、用户ID和随机数的组合&#xff1b;基于请求的来源与客户端生成的唯一序列号组合 2.方案…

代码安全规范1.1

命令注入是指应用程序执行命令的字符串或字符串的一部分来源于不可信赖的数据源&#xff0c;程序没有对这 些不可信赖的数据进行验证、过滤&#xff0c;导致程序执行恶意命令的一种攻击方式。 例 1 &#xff1a;以下代码通过 Runtime.exec() 方法调用 Windows 的 dir 命…

Jenkins实现自动化部署Springboot项目到Docker容器(Jenkinsfile)

Jenkins实现自动化部署Springboot项目到Docker容器 引言:为什么需要自动化部署? 在软件开发中,频繁的手动部署既耗时又容易出错。通过 Docker + Jenkins + Git 的组合,您可以实现: ✅ 一键部署:代码推送后自动构建和部署🐳 环境一致性:Docker 确保开发、测试、生产环…

第二届智慧教育与计算机技术国际学术会议(IECT 2025)

在数字化浪潮中&#xff0c;智慧教育与计算机技术的深度融合正重构教育生态。智能教学系统打破传统课堂的单向灌输模式&#xff0c;通过机器学习分析学习数据&#xff0c;为学生生成个性化学习路径&#xff0c;推动被动接受向主动探索转型。这对教育体系提出核心诉求&#xff1…