Linux的编译器
程序编译的过程
程序的编译过程是将源代码转换为可执行文件的一系列步骤。这个过程涉及多个阶段,主要包括预处理、编译、汇编和链接。下面详细介绍每个阶段:
1. 预处理(Preprocessing)
在实际编译之前,源代码文件首先经过预处理器处理。预处理阶段主要处理那些以井号(#)开头的指令,如宏定义(#define)、文件包含(#include)等。预处理器执行的任务包括:
- 宏展开:将所有的宏定义替换为相应的值。
- 文件包含:将包含指令(#include)指定的文件内容插入到源代码文件中。
- 条件编译:根据特定的条件编译指令,决定是否编译代码的特定部分。
- 移除注释:从源代码中移除所有注释。
2. 编译(Compilation)
预处理后的代码(现在是纯文本)被送到编译器,编译器将其转换成汇编代码。编译阶段的主要任务是:
- 语法分析:检查代码是否符合语言的语法规则。
- 语义分析:检查代码中的表达式和语句是否有意义(比如类型检查)。
- 生成中间代码:生成一种更接近机器语言的中间表示形式,通常是汇编语言。
3. 汇编(Assembly)
汇编器接收编译阶段生成的汇编代码,将其转换为机器码(二进制代码)。每一条汇编指令几乎直接对应一条机器指令。生成的输出通常是目标文件(.o 或 .obj 文件),这些文件包含了程序的机器语言表示。
4. 链接(Linking)
程序通常由多个源代码文件组成,这些文件需要被单独编译和汇编。链接器的任务是将一个或多个目标文件合并成一个单一的可执行文件。在链接过程中,链接器还会解决程序中各个部分之间的引用和依赖问题,例如:
- 解析外部引用:处理程序不同部分或外部库之间的调用关系。
- 地址绑定:确定程序和数据在内存中的位置。
- 库链接:将程序需要的库(动态链接库或静态库)合并到最终的可执行文件中。
完整的流程图
源代码 -> [预处理] -> 预处理后的代码 -> [编译] -> 汇编代码 -> [汇编] -> 目标代码 -> [链接] -> 可执行文件
这个过程是高度自动化的,通常由构建系统(如 Makefiles、CMake 等)控制,它会根据需要执行上述所有步骤,生成最终的可执行程序。每个阶段都有专门的工具和软件来执行,比如 GCC 或 Clang(在 C/C++ 开发中)等。
语言自举的过程
语言自举(Bootstrapping a language)是一种使用编程语言的编译器或解释器来编写该语言本身的编译器或解释器的过程。简而言之,这意味着用一种语言编写该语言自身的编译器或解释器。这个过程中,该语言的初期版本通常是用另一种语言编写的,而后续版本则可能完全或部分使用该语言自身来进行重写或优化。
自举过程的步骤
-
初始实现:在最开始,编程语言的编译器或解释器通常用另一种已存在的语言编写。这样做是因为初始的编程语言还没有足够的工具和支持来自我编译。
-
自我编译:当这种新语言发展到足够成熟,可以支持更复杂的功能时,开发者会使用这种语言自身来重写其编译器或解释器。这意味着新语言现在可以编译自己的编译器,这通常被看作是一种成熟的标志。
-
优化和扩展:一旦编译器可以用其自身的语言成功编译,开发者就可以继续使用该语言来优化和扩展编译器的功能。这可能包括添加新的语言特性、优化性能或改进错误处理。
-
迭代改进:随着时间的推移,编译器可以不断通过自身来进行迭代改进和更新,这增强了其功能和效率,并可以支持新的编程范式或标准。
自举的优势
- 独立性:自举减少了对其他编程语言的依赖,使得编程语言及其工具链更加独立。
- 演示能力:使用一种语言编写其自身的编译器是对该语言功能强大和成熟度的展示。
- 自我验证:自举过程可以作为一种验证手段,证明语言足够强大,能够处理复杂的编程任务,如编写和处理编译器代码。
自举的例子
- C语言:C语言最初的编译器是用汇编语言编写的,但很快之后,C的编译器就开始用C语言本身来编写,这是最著名的自举案例之一。
- Pascal:Niklaus Wirth 设计的 Pascal 语言也是先用其他语言编写了编译器,后来用 Pascal 自身重写。
- Rust:Rust 语言最初的编译器是用 OCaml 编写的,现在的 Rust 编译器(rustc)主要用 Rust 本身编写。
gcc / g++
GCC(GNU Compiler Collection)是一个开源的编译器套件,支持多种编程语言,其中最为人熟知的是 C 和 C++(通过 G++ 编译器)。GCC 是在自由软件基金会(FSF)的 GNU 项目下开发的,旨在提供一个标准的、高性能、高可靠性的编译器,它在开源和自由软件开发中占有非常重要的地位。
-
多语言支持:GCC 最初是作为一个 C 语言编译器开始的,但后来扩展到支持多种语言,包括 C++(G++)、Objective-C、Fortran、Ada、Go,以及 Java 等。
-
跨平台:GCC 可以在多种类型的操作系统上运行,包括 Linux、Mac OS、Windows(通常通过 MinGW 或 Cygwin)等,支持广泛的架构,如 x86、x64、ARM、PowerPC 等。
-
代码优化:GCC 提供了多种级别的优化选项,可以帮助开发者提高程序的执行效率。从
-O0
(无优化)到-O3
(最大优化),还有-Os
(优化空间)和-Ofast
(忽略严格标准的最快速优化)。 -
标准遵从:GCC 高度遵循各个编程语言的标准,如 ISO C、C++,并定期更新以支持最新的语言标准。
-
调试和错误报告:GCC 提供详细的错误和警告消息,帮助开发者诊断代码问题。配合 GDB(GNU Debugger)使用,可以有效地进行代码调试。
-
扩展性:GCC 也支持内联汇编,允许开发者插入架构特定的汇编代码来优化程序,同时支持自定义的编译器插件。
G++ 是 GCC 中的 C++ 编译器,支持 C++ 的所有标准特性,包括最新的 C++20 标准。G++ 不仅能够编译复杂的 C++ 应用程序和库,还支持异常处理、模板编程等现代 C++ 特性。
动态库&&静态库
静态库和动态库是在软件开发中用来实现代码重用和模块化的两种不同类型的库。它们主要的区别在于它们如何被集成和使用在应用程序中。
静态库
静态库是一种在程序编译时期就已经被包含进程序的库。它们通常包含一组编译好的代码,这些代码可以直接链接到最终的可执行文件中。
- 集成方式:在编译阶段,静态库中的代码被复制到最终的可执行文件中。这个过程是由链接器完成的,链接器将程序中用到的静态库中的对象文件直接集成到程序的可执行文件中。
- 部署和分发:由于静态库的内容已经被集成到可执行文件中,所以这些程序在分发时不需要附带这些库文件。可执行文件本身就包含了所有必要的代码。
动态库
动态库是一种在程序运行时才加载的库。它们的代码在程序运行时被载入内存,并通过操作系统进行管理。
- 集成方式:动态库并不是在编译时被包含进可执行文件,而是在程序运行时由操作系统动态地加载。程序在运行时会请求操作系统加载所需的库,并将其链接到正在运行的程序中。
- 部署和分发:因为动态库不是程序的一部分,所以在分发这些程序时,需要确保动态库可以在目标系统上被访问。通常,动态库需要与程序一起分发,或者确保目标系统已经安装了相应的库。
区别
- 链接时期:静态库在编译时被集成,动态库在运行时被加载。
- 体积影响:使用静态库的程序通常体积更大,因为所有需要的库代码都被包含在内;使用动态库的程序体积更小,但需要在运行环境中有对应的库。
- 运行依赖:静态库的程序运行时不依赖外部库文件,而动态库的程序需要在运行时环境中访问这些库。
- 更新和维护:动态库更易于更新和维护,因为只需替换单个库文件即可影响所有使用该库的程序;静态库的更新需要重新编译和分发整个程序。
相关文章:

Linux的编译器
程序编译的过程 程序的编译过程是将源代码转换为可执行文件的一系列步骤。这个过程涉及多个阶段,主要包括预处理、编译、汇编和链接。下面详细介绍每个阶段: 1. 预处理(Preprocessing) 在实际编译之前,源代码文件首…...

redis--安装
简介 官网:RedisInsight - The Best Redis GUI 各个版本官网下载地址:http://download.redis.io/releases/ Redis和Memcached是非关系型数据库也称为NoSQL数据库,MySQL、Mariadb、SQL Server、PostgreSQL Oracle 数据库属于关系型数据 应用…...

魔法程序员的奥妙指南:Java基本语法
作为一名魔法程序员,精通Java语言是至关重要的。Java作为一种强大的编程语言,在编写优质代码和开发强大应用程序时发挥着重要作用。让我们深入探讨Java基本语法的关键要点,从注释到变量,无所不包! Java基本语法的神秘魔…...

SpringMVC传递参数
1.RequestMapping RequestMapping本身可以处理,get或post,指定了get或post之后,就只能处理对应的请求。 RequestMapping(value{"haihiyo","goodMoring"},methodRequestMethod.POST)2.RestFul风格 RestFul是一种风格 比如:网站的访…...

【Scala---04】函数式编程 『 函数 vs 方法 | 函数至简原则 | 函数式编程』
文章目录 1. 函数 vs 方法1.1 方法(1) 定义方法(2) 运算符即方法 1.2 函数(1) 定义函数(2) 匿名函数 1.3 方法转为函数1.4 可变参数&默认参数 2. 函数至简原则3. 函数式编程3.1 函数式编程思想3.3 函数柯里化&闭包3.5 递归 & 尾递归 4. 补充4.1 访问元祖元素4.2 &g…...

[华为OD] B卷 树状结构查询 200
题目: 通常使用多行的节点、父节点表示一棵树,比如 西安 陕西 陕西 中国 江西 中国 中国 亚洲 泰国 亚洲 输入一个节点之后,请打印出来树中他的所有下层节点 输入描述 第一行输入行数,下面是多行数据,每行以空…...

基于机器学习的学生学习行为自主评价设计与实现
管理员功能: a)学生学习数据管理:可查看学生学习的详情,编辑学生学习的内容,删除和添加学生学习,设置学生学习库存。 b)角色管理:增加删除学生用户,分配学生用户权限,查看学生用户…...
toml与json联系对比
前言 本文简单介绍toml;并且和json转化做对比,以及我对toml设计的理解。 参考: TOML: 简体中文 v1.0.0 json和toml转化工具 在线JSON转toml-toml转JSON - bejson在线工具 正文 数组 说白了,就是一个变量名,有多个…...

(已解决)org.springframework.amqp.rabbit.support.ListenerExecutionFailedException
报错截图 解决方案 1、登录rabbitMQ网址,删除所有队列 2、重启rabbitMQ 亲测有效!!!亲测有效!!!亲测有效!!!...

基于FPGA的数字信号处理(9)--定点数据的两种溢出处理模式:饱和(Saturate)和绕回(Wrap)
1、前言 在逻辑设计中,为了保证运算结果的正确性,常常需要对结果的位宽进行扩展。比如2个3bits的无符号数相加,只有将结果设定为4bits,才能保证结果一定是正确的。不然,某些情况如77 14(1110),如果结果只…...
基于STM32的宠物箱温度湿度监控系统毕业设计
基于STM32的宠物箱温度湿度监控系统毕业设计 一、项目背景与意义 随着人们生活水平的提高,养宠物已经成为一种流行趋势。然而,对于宠物的居住环境,尤其是温度与湿度的控制,是确保宠物健康的关键。本项目旨在设计一款基于STM32微…...

Linux sudo 指令
sudo命令 概念: sudo是linux下常用的允许普通用户使用超级用户权限的工具,允许系统管理员让普通用户执行一些或者全部的root命令,如halt,reboot,su等。这样不仅减少了root用户的登录和管理时间,同样也提高…...
【NumPy数组】:深入了解numpy.linspace()函数
一、numpy.linspace()函数的原理 numpy.linspace()函数的核心原理是在指定的起始值和终止值之间,按照给定的元素个数,生成等间隔的数值序列。与numpy.arange()函数不同,numpy.linspace()生成的是等间隔的数值,而不是等差的数值&a…...
计算机网络实验二:交换机的基本配置与操作
实验二:交换机的基本配置与操作 一、实验要求 (1)掌握windows网络参数的设置(TCP/IP协议的设置); (2)掌握交换机命令行各种操作模式的区别,以及模式之间的切换; (3)掌握交换机的全局的基本配置; (4)掌握交换机端口的常用配置参数; (5)查看交换机系统和…...

宏的优缺点?C++有哪些技术替代宏?(const)权限的平移、缩小
宏的优缺点? 优点: 1.增强代码的复用性。【减少冗余代码】 2.提高性能,提升代码运行效率。 缺点: 1.不方便调试宏。(因为预编译阶段进行了替换) 2.导致代码可读性差,可维护性差࿰…...

2024数维杯数学建模选题建议及各题思路来啦!
大家好呀,2024数维杯数学建模挑战赛开始了,来说一下初步的选题建议吧: 首先定下主基调, 本次数维杯建议选B。难度上C>A>B。B题目是比较经典的数据分析类题目,主要做统计分析差异显著性以及相关…...
centos的常用命令
CentOS是一个基于Red Hat Enterprise Linux(RHEL)的开源操作系统,常用于服务器环境。以下是一些CentOS中常用的命令: 文件和目录管理: ls:列出目录中的文件。 ls -l:以长格式列出文件和目录的…...
【Android】使用Handler实现一个定时器
需求 实现一个定时任务,每隔一秒执行一次 实现 使用Handler实现 private Handler topUIHandler;private void initTopUiHandler() {topUIHandler new Handler(getMainLooper()) {Overridepublic void handleMessage(Message msg) {//执行这个定时任务updateTop…...

Java | Leetcode Java题解之第80题删除有序数组中的重复项II
题目: 题解: class Solution {public int removeDuplicates(int[] nums) {int n nums.length;if (n < 2) {return n;}int slow 2, fast 2;while (fast < n) {if (nums[slow - 2] ! nums[fast]) {nums[slow] nums[fast];slow;}fast;}return sl…...

java后端15问!
前言 最近一位粉丝去面试一个中厂,Java后端。他说,好几道题答不上来,于是我帮忙整理了一波答案 G1收集器JVM内存划分对象进入老年代标志你在项目中用到的是哪种收集器,怎么调优的new对象的内存分布局部变量的内存分布Synchroniz…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...