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

C语言从入门到实战——编译和链接

编译和链接

  • 前言
  • 一、 翻译环境和运行环境
  • 二、 翻译环境
    • 2.1 预处理(预编译)
    • 2.2 编译
      • 2.2.1 词法分析
      • 2.2.2 语法分析
      • 2.2.3 语义分析
    • 2.3 汇编
    • 2.4 链接
  • 三、 运行环境


前言

在C语言中,编译和链接是将源代码转换为可执行文件的两个主要步骤。

编译过程包括以下步骤:

  1. 预处理:将源代码中的预处理指令(如#include#define)替换为实际的代码。
  2. 编译:将预处理后的代码转换为汇编语言。
  3. 汇编:将汇编语言转换为机器码指令。

链接过程包括以下步骤:

  1. 目标文件生成:将每个源文件编译后生成的目标文件(.o.obj)进行合并,生成一个总的目标文件。
  2. 符号解析:查找并解析目标文件中的所有符号(例如全局变量和函数名),以确保每个符号都有一个唯一的地址。
  3. 地址重定位:根据符号表中符号的地址信息,将目标文件中的所有地址引用进行重定位,使它们指向正确的地址。
  4. 符号解析和重定位完成后,将链接后的目标文件与标准库和其他库文件进行链接,生成最终的可执行文件。

在编译和链接过程中,可以使用不同的编译器和链接器来完成这些步骤。常见的C语言编译器包括GCCClangMSVC等,而常见的链接器包括GNU ldMicrosoft Linker等。

编译器和链接器的具体命令和选项可以根据不同的平台和编译环境而有所不同,可以通过编译器和链接器的帮助文档或命令行参数来了解更多信息。


一、 翻译环境和运行环境

ANSIC是一种计算机编程语言,全称为American National Standard Institute C。它是C语言的一个标准化版本,于1989年被美国国家标准学会(ANSI)采纳为正式的国家标准。ANSIC在C语言的基础上进行了一些改进和扩展,增加了一些新的特性和功能,提高了代码的可读性和可靠性。ANSIC的标准化使得不同厂商的编译器能够遵循相同的规范,从而实现了C语言的跨平台性和移植性。

ANSIC的任何一种实现中,存在两个不同的环境。

第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。

第2种是执行环境,它用于实际执行代码。
在这里插入图片描述

二、 翻译环境

那翻译环境是怎么将源代码转换为可执行的机器指令的呢?这里我们就得展开讲解一下翻译环境所做的事情。

其实翻译环境是由编译和链接两个大的过程组成的,而编译又可以分解成:预处理(有些书也叫预编译)、编译、汇编三个过程。
在这里插入图片描述
一个C语言的项目中可能有多个 .c 文件一起构建,那多个 .c 文件如何生成可执行程序呢?

  • 多个.c文件单独经过编译出编译处理生产对应的目标文件。
  • 注:在Windows环境下的目标文件的后缀是 .objLinux环境下目标文件的后缀是 .o
  • 多个目标文件和链接库一起经过链接器处理生成最终的可执行程序。
  • 链接库是指运行时库(它是支持程序运行的基本函数集合)或者第三方库。

如果再把编译器展开成3个过程,那就变成了下面的过程:
在这里插入图片描述

2.1 预处理(预编译)

在预处理阶段,源文件和头文件会被处理成为.i为后缀的文件。

gcc 环境下想观察一下,对 test.c 文件预处理后的.i文件,命令如下:

gcc -E test.c -o test.i

预处理阶段主要处理那些源文件中#开始的预编译指令。

比如:#include,#define,处理的规则如下:

  • 将所有的 #define 删除,并展开所有的宏定义。
  • 处理所有的条件编译指令,如: #if#ifdef#elif#else#endif
  • 处理#include 预编译指令,将包含的头文件的内容插入到该预编译指令的位置。

这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。

  • 删除所有的注释
  • 添加行号和文件名标识,方便后续编译器生成调试信息等。
  • 或保留所有的#pragma的编译器指令,编译器后续会使用。

经过预处理后的.i文件中不再包含宏定义,因为宏已经被展开。并且包含的头文件都被插入到.i入件中。所以当我们无法知道宏定义或者头文件是否包含正确的时候,可以查看预处理后的.i文件来确认。

2.2 编译

编译过程就是将预处理后的文件进行一系列的:词法分析、语法分析、语义分析及优化,生成相应的汇编代码文件。

编译过程的命令如下:

gcc -S test.i -o test.s 

对下面代码进行编译的时候,会怎么做呢?

假设有下面的代码

array[index] = (index+4)*(2+6); 

2.2.1 词法分析

将源代码程序被输入扫描器,扫描器的任务就是简单的进行词法分析,把代码中的字符分割成一系列的记号(关键字、标识符、字面量、特殊字符等)。

上面程序进行词法分析后得到了16个记号:

记号类型
array标识符
[左方括号
index标识符
]右方括号
=赋值
左圆括号
index标识符
+加号
4数字
右圆括号
2数字
+加号
6数字
右圆括号

2.2.2 语法分析

接下来语法分析器,将对扫描产生的记号进行语法分析,从而产生语法树。这些语法树是以表达式为节点的树。

在这里插入图片描述

2.2.3 语义分析

由语义分析器来完成语义分析,即对表达式的语法层面分析。编译器所能做的分析是语义的静态分析。静态语义分析通常包括声明和类型的匹配,类型的转换等。这个阶段会报告错误的语法信息。

在这里插入图片描述

2.3 汇编

汇编器是将汇编代码转转变成机器可执行的指令,每一个汇编语句几乎都对应一条机器指令。就是根据汇编指令和机器指令的对照表一一的进行翻译,也不做指令优化。

汇编的命令如下:

gcc -c test.s -o test.o 

2.4 链接

链接是一个复杂的过程,链接的时候需要把一堆文件链接在一起才生成可执行程序。

链接过程主要包括:地址和空间分配,符号决议和重定位等这些步骤。

链接解决的是一个项目中多文件、多模块之间互相调用的问题。

比如:在一个C的项目中有2个.c文件( test.cadd.c ),代码如下:
在这里插入图片描述
test.c

#include <stdio.h>
//test.c
//声明外部函数
extern int Add(int x, int y);
//声明外部的全局变量
extern int g_val;
int main()
{int a = 10;int b = 20;int sum = Add(a, b);printf("%d\n", sum);return 0;
}

add.c

int g_val = 2022;
int Add(int x, int y)
{return x+y;
}

我们已经知道,每个源文件都是单独经过编译器处理生成对应的目标文件。

test.c 经过编译器处理生成 test.o
add.c 经过编译器处理生成 add.o

我们在 test.c 的文件中使用了 add.c 文件中的 Add 函数和 g_val 变量。

我们在 test.c 文件中每一次使用Add 函数和 g_val 的时候必须确切的知道 Addg_val 的地址,但是由于每个文件是单独编译的,在编译器编译 test.c 的时候并不知道 Add 函数和 g_val变量的地址,所以暂时把调用Add 的指令的目标地址和 g_val 的地址搁置。等待最后链接的时候由链接器根据引用的符号 Add 在其他模块中查找 Add 函数的地址,然后将 test.c 中所有引用到Add 的指令重新修正,让他们的目标地址为真正的 Add 函数的地址,对于全局变量 g_val 也是类似的方法来修正地址。这个地址修正的过程也被叫做:重定位。

前面我们非常简洁的讲解了一个C的程序是如何编译和链接,到最终生成可执行程序的过程,其实很多内部的细节无法展开讲解。比如:目标文件的格式elf,链接底层实现中的空间与地址分配,符号解析和重定位等,如果你有兴趣,可以看《程序的自我修养》一书来详细了解。

在这里插入图片描述

三、 运行环境

  1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
  2. 程序的执行便开始。接着便调用main函数。
  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
  4. 终止程序。正常终止main函数;也有可能是意外终止。

相关文章:

C语言从入门到实战——编译和链接

编译和链接 前言一、 翻译环境和运行环境二、 翻译环境2.1 预处理&#xff08;预编译&#xff09;2.2 编译2.2.1 词法分析2.2.2 语法分析2.2.3 语义分析 2.3 汇编2.4 链接 三、 运行环境 前言 在C语言中&#xff0c;编译和链接是将源代码转换为可执行文件的两个主要步骤。 编…...

【实战教程】ThinkPHP6分页功能轻松实现,让你的网站更高效!

ThinkPHP是一款非常流行的PHP开发框架&#xff0c;其最新版本ThinkPHP6在性能和易用性方面都得到了很大的改善。分页功能是网页开发中非常常见的功能&#xff0c;而ThinkPHP6也提供了非常方便的分页方法。本文将介绍如何实现ThinkPHP6的分页功能。 一、了解分页功能 在Web应用…...

专业130+总分380+哈尔滨工程大学810信号与系统考研经验水声电子信息与通信

今年专业课810信号与系统130&#xff0c;总分380顺利考上哈尔滨工程大学&#xff0c;一年的努力终于换来最后的录取&#xff0c;期中复习有得有失&#xff0c;以下总结一下自己的复习经历&#xff0c;希望对大家有帮助&#xff0c;天道酬勤&#xff0c;加油&#xff01;专业课&…...

旅游项目day08

1. 旅游日记&#xff08;游记&#xff09; 后端&#xff1a;实体类&#xff0c;列表&#xff0c;查看&#xff0c;审核 前端&#xff1a;目的地明细中-游记->带范围条件查询&#xff0c;游记首页&#xff0c;【扩展】游记添加/编辑&#xff0c;【扩展】添加游记时间没登录时…...

蓝桥杯真题(Python)每日练Day2

题目 题目分析 对于本题首先确定其数据结构为优先队列&#xff0c;即邮费最小的衣服优先寄&#xff0c;算法符合贪心算法。可以直接使用queue库的PriorityQueue方法实现优先队列。关于PriorityQueue的使用方法主要有&#xff1a; import queue q queue.Queue()# 队列 pq qu…...

IntelliJ IDEA 拉取gitlab项目

一、准备好Gitlab服务器及项目 http://192.168.31.104/root/com.saas.swaggerdemogit 二、打开 IntelliJ IDEA安装插件 打开GitLab上的项目&#xff0c;输入项目地址 http://192.168.31.104/root/com.saas.swaggerdemogit 弹出输入登录用户名密码&#xff0c;完成。 操作Comm…...

RHCSA上课笔记(前半部分)

第一部分 网络服务 第一章 例行性工作 1.单一执行的例行性工作 单一执行的例行性工作&#xff08;就像某一个时间点 的闹钟&#xff09;&#xff1a;仅处理执行一次 1.1 at命令&#xff1a;定时任务信息 [rhellocalhost ~]$ rpm -qa |grep -w at at-spi2-core-2.40.3-1.el9.x…...

C++代码入门05 字符串容器

图源&#xff1a;文心一言 上机题目练习整理&#xff0c;本篇作为字符串容器的代码&#xff0c;提供了常规解法及其详细解释&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 第1版&#xff1a;在力扣新手村刷题的记录~&#x1f9e9;&#x1f9e9; 方法&#xff1a;常…...

vue3 项目中 arguments 对象获取失败问题

问题 在 vue3 项目中 获取到的 arguments 对象与传入实参不符&#xff0c;打印出函数中的 arguments 对象显示如下&#xff1a; 原因 作者仔细回看代码才发现&#xff0c;自己一直用的是 vue3 的组合式写法&#xff0c;函数都是箭头函数&#xff0c;而箭头函数不存在 argumen…...

12.线程同步

12.线程同步 1. 为什么需要线程同步2. 互斥锁2.1 互斥锁初始化2.1.1 PTHREAD_MUTEX_INITIALIZER 宏初始化2.1.2 使用函数初始化 2.2 加锁和解锁2.3 pthread_mutex_trylock()2.4 销毁互斥锁2.5 互斥锁死锁2.6 互斥锁的属性 3. 条件变量3.1 条件变量初始化3.2 通知和等待条件变量…...

开发安全之:System Information Leak: External

Overview 在调用 error_reporting() 过程中&#xff0c;程序可能会显示系统数据或调试信息。由 error_reporting() 揭示的信息有助于攻击者制定攻击计划。 Details 当系统数据或调试信息通过套接字或网络连接使程序流向远程机器时&#xff0c;就会发生外部信息泄露。 示例 1…...

burp靶场--文件上传

burp靶场–文件上传 https://portswigger.net/web-security/file-upload/lab-file-upload-remote-code-execution-via-web-shell-upload 1.文件上传 1、原理&#xff1a;文件上传漏洞是指Web服务器允许用户将文件上传到其文件系统&#xff0c;而不充分验证文件的名称、类型、…...

mac 中vscode设置root启动

1. 找到你的vscode app&#xff0c;点击鼠标右键------->选项----->在访达中显示 2. 终端中输入以下命令&#xff0c;不要点回车&#xff0c;不要点回车&#xff0c;输入一个空格 sudo chflags uchg 3. 然后将你的程序拖到终端&#xff0c;会自动…...

【MySQL数据库专项 一】一个例子讲清楚数据库三范式

好的&#xff0c;让我们以学校数据库中的一个表为例来说明第一范式&#xff08;1NF&#xff09;、第二范式&#xff08;2NF&#xff09;和第三范式&#xff08;3NF&#xff09;的概念。 什么是数据库三范式 数据库的范式&#xff08;Normalization&#xff09;是一组关于数据…...

【笔记】关于期刊

什么是统计源期刊 统计源期刊&#xff0c;全称为“中国科技论文统计源期刊”&#xff0c;也称作中国科技核心期刊&#xff0c;是由中国科技信息研究所&#xff08;ISTIC&#xff09;受国家科技部委托&#xff0c;选定的一系列在中国出版的高质量自然科学类学术期刊。这些期刊是…...

SpringMVC-.xml的配置

文章目录 一、对pom.xml的配置二、对web.xml1.第一种方式2. 第二种方式 三、对SpringMVC.xml的配置 一、对pom.xml的配置 <!-- 打包成war包--><packaging>war</packaging> <dependencies><!-- SpringMVC--><dependency><gro…...

Java找二叉树的公共祖先

描述&#xff1a; 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节…...

《Linux高性能服务器编程》笔记03

Linux高性能服务器编程 本文是读书笔记&#xff0c;如有侵权&#xff0c;请联系删除。 参考 Linux高性能服务器编程源码: https://github.com/raichen/LinuxServerCodes 豆瓣: Linux高性能服务器编程 文章目录 Linux高性能服务器编程第07章 Linux服务器程序规范7.1日志7.2用…...

Java毕业设计-基于ssm的网上求职招聘管理系统-第85期

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于ssm的网上求职招聘管理系统&#xff1a;前端 jsp、jquery&#xff0c;后端 springmvc、spring、mybatis&#xff0c;角色分为管理员、招聘人员、用户&#xff1b;集成…...

UDP和TCP

UDP协议是一种不可靠的、面向无连接的协议。在通信过程中&#xff0c;它并不像TCP那样需要先建立一个连接&#xff0c;只要&#xff08;目的地址&#xff0c;端口号&#xff0c;源地址&#xff0c;端口号&#xff09;确定了&#xff0c;就可以直接发送信息报文&#xff0c;并且…...

为什么你的无锁队列在压测中崩了——从 ABA 问题到 Hazard Pointer,追踪 lock-free 内存回收的生死时序

你的 lock-free queue 通过了所有单元测试,在 4 线程环境下稳定跑了整整一周,性能数据漂亮,直到你把压测线程数拉到 64,跑了 17 分钟后收到 SIGSEGV,打开 coredump 一看,崩溃地址指向的那块内存已经被 free 掉又被另一次 enqueue 重新 allocate 成了一个全新的节点,而 d…...

从COCO到自定义:用Labelme为YOLOv8-Pose制作关键点数据集的完整避坑指南

从COCO到自定义&#xff1a;用Labelme为YOLOv8-Pose制作关键点数据集的完整避坑指南 在计算机视觉领域&#xff0c;关键点检测技术正逐渐成为工业界和学术界的热点研究方向。不同于传统的目标检测任务&#xff0c;关键点检测不仅需要定位物体位置&#xff0c;还要精确识别物体内…...

DeepSeek-R1 MoE架构逆向工程报告(基于HuggingFace源码+NCCL trace分析):专家粒度、FFN维度与token路由热力图首次披露

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;DeepSeek-R1 MoE架构逆向工程总览 DeepSeek-R1 是一款基于稀疏混合专家&#xff08;Mixture of Experts, MoE&#xff09;架构的大语言模型&#xff0c;其推理与训练行为在公开文档中未完全披露。本章聚焦于通…...

别再死磕原生OpenStack了!华为云Stack HCS 8.0的极简部署与高可用设计,真香!

华为云Stack HCS 8.0&#xff1a;企业私有云部署的革命性突破 当企业IT架构师面对私有云平台选型时&#xff0c;部署复杂性和系统可靠性往往成为最令人头疼的两大难题。原生OpenStack以其高度灵活性和开源特性吸引了大量技术团队&#xff0c;但随之而来的却是漫长的部署周期、繁…...

体验Taotoken在多模型间智能路由与故障转移对大赛服务稳定性的提升

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 体验Taotoken在多模型间智能路由与故障转移对大赛服务稳定性的提升 在组织一场线上编程大赛时&#xff0c;后台的智能判题与实时答…...

日志分析 Elasticsearch 和 logstach.filebeat.

一、Elasticsearch 到底是啥&#xff1f;简单说&#xff0c;ES 就是一个能飞速搜索和分析海量数据的搜索引擎。类似百度、谷歌&#xff0c;但它是给你公司内部的数据用的。比如&#xff1a;淘宝搜商品&#xff0c;输入“手机 拍照好”&#xff0c;毫秒级给你结果——背后就是 E…...

MTK手机用上高通QC快充,背后多出的那颗‘xmusb350’芯片到底在忙啥?

MTK手机为何需要外挂xmusb350芯片实现高通QC快充&#xff1f; 当你在电商平台搜索"支持QC快充的MTK手机"时&#xff0c;可能会发现一个有趣的现象&#xff1a;采用联发科处理器的机型在充电模块描述中&#xff0c;常会特别标注"搭载独立QC协议芯片"。这背后…...

开发雨天居家室内活动推荐程序,根据人数年龄自动生成雨天居家休闲创意活动。

一个完全去营销化、偏工程与创业实验视角的 Python 示例项目&#xff0c;定位为课程级 MVP 原型&#xff0c;不绑定任何平台、不推荐商品、不引导消费。雨天居家室内活动推荐程序——基于人数与年龄的规则推荐系统实验一、实际应用场景描述在下雨天气&#xff0c;家庭或室友常面…...

为什么顶级作曲家都在弃用Shazam转投Perplexity?——基于127万条音乐查询日志的权威对比报告

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;Perplexity音乐知识搜索的崛起背景与行业影响 近年来&#xff0c;音乐产业正经历从“内容分发”向“知识理解”的范式迁移。传统搜索引擎在处理音乐相关查询时&#xff0c;常受限于语义模糊性——例如用户输入…...

从莱顿瓶到手机:一个300年前的“水罐”如何塑造了今天的电子世界?

从莱顿瓶到手机&#xff1a;一个300年前的“水罐”如何塑造了今天的电子世界&#xff1f; 1746年&#xff0c;法国物理学家诺莱特在巴黎科学院进行了一场令人瞠目的公开实验&#xff1a;700名僧侣手拉手排成1.5公里长的人链&#xff0c;当首尾两端连接莱顿瓶时&#xff0c;所有…...