gcc编译过程

article/2025/10/2 16:00:23

一、总体概述

GCC的编译流程分为四个步骤:
1、预处理(Pre-Processing)
2、编译(Compiling)
3、汇编 (Assembliang)
4、链接(Linking)

二、解释步骤

XXX为源文件
YY为生成的文件
1、预处理(Pre-Processing)
预处理用于将所有的#include头文件以及宏定义替换成其真正的内容,预处理之后得到的仍然是文本文件,但文件体积会大很多。
将 .c 文件转换为 .i 文件,使用gcc命令:gcc -E XXX -o YY
对应于预处理命令 cpp
2、编译(Compiling)
将预处理之后的程序转换为特定的汇编代码 (assembly code) 的过程。
将 .c/.h 文件转换为 .s 文件,使用gcc命令:gcc -S XXX -o YY
对应于编译命令 cc -S
3、汇编 (Assembliang)
汇编过程将上一步的汇编代码转成机器码(machine code),这一步产生的文件叫 目标文件 ,是二进制格式。此步骤会为每一个源文件产生一个目标文件。
将 .s 文件转换为 .o 文件,使用gcc命令:gcc -c XXX -o YY
对应于汇编命令 as
4、链接(Linking)
链接过程将多个目标文件以及所需的库文件( .so 等)链接成最终可执行文件(executable file)。
将 .o 文件转换为 可执行程序,使用gcc命令: gcc -o YY XXX
对应于链接命令 ld
总结起来编译过程就上面的四个过程:预编译处理(.c) --> 编译、优化程序(.s、.asm)--> 汇编程序(.obj、.o、.a、.ko) --> 链接程序(.exe、.elf、.axf等)。

三、案例

结果展示
编译过程

四、个人练习

目录结构

├── test.c
└── inc├── mymath.h└── mymath.c

demo源文件

// test.c
#include <stdio.h>
#include "mymath.h"// 自定义头文件
int main(){int a = 2;int b = 3;int sum = add(a, b); printf("a=%d, b=%d, a+b=%d\n", a, b, sum);
}

头文件定义

// mymath.h
#ifndef MYMATH_H
#define MYMATH_H
int add(int a, int b);
int sum(int a, int b);
#endif

头文件实现

// mymath.c
int add(int a, int b){return a+b;
}
int sub(int a, int b){return a-b;
}

--------------------------------------------------------------------分隔线------------------------------------------------------------
编译过程
1、预处理
gcc -E -I./inc/ test.c -o test.i
2、编译
gcc -S -I./inc test.c -o test.s
3、汇编
gcc -c test.s -o test.o
执行到此步骤时,需要生成其他目标文件,例如 mymath.o
如下执行:
cd inc/
gcc -E mymath.c -o mymath.i
gcc -S mymath.i -o mymath.s
gcc -c mymath.s -o mymath.o
4、链接
gcc -o test.out test.o ./inc/mymath.o

结果图
一个目标文件生成步骤
总图

五、补充

Makefile
Makefie

GCC的基本用法和选项
GCC的最基本用法是:gcc [options] [filenames]
-c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o的后缀的目标文件,通常用于编译不包含主程序的子程序文件。
-o output filename ,确定输出文件名称为output filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
-g,产生符号调试工具(GUN的gdb)所必要的符号资讯,想要对源代码进行调试,我们必须加入这个选项
-O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度会相对慢一些。
-O2,比-O更好的优化编译、连接,当然整个编译、连接过程会很慢。
-I dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。
-L dirname,将dirname 所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数。
GCC的错误类型及对策
第一类:C语法错误
错误信息:文件source.c中第n行语法错误(systex error)。有些情况下,一个简单的语法错误,gcc会出一大堆错误,我们要保持头脑清醒,不要被吓到!
第二类:头文件错误
错误信息:找不到头文件head.h(Can not find include file head.h)。这类错误是源代码文件中的包含头文件有问题,可能的原因有头文件名错误、指定的头文件所在目录名错误等,也可能是错误的使用双引号和尖括号。
第三类:档案库错误
错误信息:链接程序找不到所需的函数库(ld:-lm:No such file or directory)。这类错误是与目标文件相连接的函数库有错误,可能的原因是函数库名错误、、指定的函数库所在目录名称错误等,检查的方法是使用find命令在可能的目录中寻找相应的函数库名,确定档案库及目录的名称并修改程序中及编译选项中的名称。
第四类:未定义符号
错误信息:有未定义的符号(Undefined symbo1)。这类错误是在连接过程中出现的,可能有两种原因:一是使用者自己定义的函数或者全局变量所在源代码文件,没有被编译连接,或者干脆还没有定义,这需要使用者根据实际情况修改源程序,给出全局变量或者函数的定义体;二是未定义的符号是一个标准的库函数,在源程序中使用了该库函数而连接过程中还没有给定相应的函数库的名称,或者是该档案库的目录名称有问题,这时需要使用档案库维护命令ar检查我们需要的库函数到底位于哪–个函数库中,确定之后,修改gcc连接选项中的-1和-L项。
其他介绍:
GNU工具
编译工具:把一个源程序编译为一个可执行程序
调试工具:能对执行程序进行源码或者汇编级调试
软件工程工具:用于协助多人开发或者大型软件项目的管理。如make、CVS、Subvision
其他工具:用于把多个文件链接成可执行文件的连接器,或者用作格式转换的工具
GCC简介
全称为GUN CC,GUN项目中符合ANSI C标准编译系统
编译如C、C++、Object C、JAVA、Fortran、Pascal、Modula-3和Ada等多种语言
GCC是可以在多种硬件平台上编译出可执行程序的超级编译器,其执行效率与一般的编辑器相比平均效率高出20%~30%
一个交叉平台编译器,适合在嵌入式平台领域的开发编译
gcc所支持后缀名解释

后缀名解释程序类型
.cC原始程序
.C/.cc/.cxxC++原始程序
.mObjective-C原始程序
.i已经过预处理的C原始程序
.ii已经经过处理的C++原始程序
.s/.S汇编语言原始程序
.h预处理文件(头文件)
.o目标文件
.a/.so编译后的库文件

编译器的主要组件
分析器:将源语言程序代码转换为汇编语言(C到汇编),所以分析器需要知道目标机器的汇编语言。
汇编器:汇编器将汇编语言代码转换为CPU可以执行的字节码。
链接器:将汇编器生成的单独的目标文件组合成可执行的应用程序。连接器需要知道这种目标格式以便于工作。
标准C库:核心的C语言库都有一个主要的C库来提供,如果在应用程序中用到了C库中的函数,这个库就会通过链接器和源代码连接来生成最终的可执行程序。
在这里插入图片描述


http://chatgpt.dhexx.cn/article/KrUKfRgB.shtml

相关文章

【Linux】gcc编译器

目录 一、什么是编译器 二、编译的过程 1.预处理 2.编译 3.汇编 4.链接 三、实际操作实例 四、总结 一、什么是编译器 简单讲&#xff0c;编译器就是将一种语言转化为另一种语言的程序&#xff0c;通常是将高级语言转化为低级语言。一个现代编译器的主要工工作流程&…

Linux下gcc编译器的安装与使用

GCC&#xff08;GNU Compiler Collection&#xff09;是由GNU开发的编程语言译器。GNU编译器套件包括C、C、 Objective-C、 Fortran、Java、Ada和Go语言前端&#xff0c;也包括了这些语言的库。在Linux上进行开发离不开GCC&#xff0c;本文将给出gcc的安装和基本使用方法。 目…

GCC编译器的安装教程(Windows环境)

GCC编译器的安装教程&#xff08;Windows环境&#xff09; 你好&#xff01;GCC 编译器是 Linux 系统下最常用的 C/C 编译器&#xff0c;大部分 Linux 发行版中都会默认安装。GCC 编译器通常以gcc命令的形式在终端&#xff08;Shell&#xff09;中使用.对于要学习Linux的朋友来…

GCC编译

目录 一、常用命令 1、简单编译 2、多个程序文件的编译 3、检错 4、库文件连接 二、GCC编译 1、准备工作 2、编译过程 3、汇编 4、链接 三、分析ELF文件 1、ELF文件的段 2、反汇编ELF 四、总结 一、常用命令 1、简单编译 &#xff08;1&#xff09;创建文件&am…

C++学习之gcc编译四步

C学习之gcc编译四步 一、linux下编写Hello World&#xff01;代码文件二、gcc编译四步1.预处理&#xff08;Preprocessing&#xff09;2.编译&#xff08;Compilation&#xff09;3.汇编&#xff08;Assembly&#xff09;4.链接&#xff08;Linking&#xff09; 三、执行四、gc…

Linux GCC编译详细

在Linux中使用gcc编译“hello.c”文件&#xff0c;只须使用最简单的指令&#xff0c;如下所示 $gcc hello.c -o hello 事实上&#xff0c;上述过程可以分解成四个部分&#xff1a;预处理&#xff08;预编译&#xff09;、编译、汇编、链接 一、预处理 首先是源代码文件“he…

gcc的编译过程

目录 一、gcc的编译过程 1.预处理 2.编译 3.汇编 4.连接 一、gcc的编译过程 平时使用gcc&#xff0c;我们新手小白似乎只会使用它编译生成./a.out。 gcc hello.c 或者就是给生成的程序一个别名。 gcc hello.c -o hello 但是gcc还有很多的用处&#xff0c;而且了解gcc的…

多线程和异步的区别

首先说明&#xff0c;这里介绍的区别可能有些浅显&#xff0c;内部更深层的原理&#xff0c;说实在的&#xff0c;我现在有点理解不了&#xff0c;大家可以参考以下两个地方&#xff0c;主要是以C#为主要语言&#xff1a; c#关于异步编程&#xff1f; C# 彻底搞懂async/await …

单线程与多线程使用场景

多线程使用时机 出现CPU资源浪费&#xff08;CPU空转&#xff09;的时候才适用多线程&#xff0c;每个核心在同一时刻只能处理一个线程&#xff0c;而逻辑处理器则是通过CPU的并发来模拟出的核心 单线程与多线程使用情况 适用单线程的情况 CPU全力执行&#xff0c;没有产生…

多线程与并发 - 进程和线程的区别

进程和线程的由来&#xff1a; 进程是资源分配的最小单位&#xff0c;线程是CPU调度的最小单位 所有与进程相关的资源&#xff0c;都被记录在PCB中进程是抢占处理机的调度单位&#xff1b;线程属于某个进程&#xff0c;共享其资源线程只由堆栈寄存器、程序计数器和线程控制表&…

多线程并发和并行的区别

背景 对于java开发从业人员来说&#xff0c;并发编程是绕不开的话题&#xff0c;juc并发包下提供了一系列多线程场景解决方案。  随着jdk1.8的普及&#xff0c;多线程处理问题&#xff0c;除了使用使用线程池(ExecutorService)&#xff0c;很多人选择了parallelStream() 并行流…

多线程与单线程理解

多线程与单线程理解 进程与线程的关系 进程是计算机程序执行一次过程的接班单位&#xff0c;即正在执行的程序&#xff08;QQ&#xff09;&#xff0c;一个应用程序可以包含多个进程&#xff08;QQ的不同页面信息&#xff09; 线程是进程的基本单元&#xff0c;一个进程至少包…

线程和进程的区别与联系以及单线程多进程与单进程多线程的区别

线程和进程 概念 进程&#xff08;process&#xff09;&#xff1a;是指具有已一定功能的独立程序&#xff0c;是系统资源分配的基本单位&#xff0c;在内存中有其完备的数据空间和代码空间&#xff0c;拥有完整的虚拟空间地址。一个进程所拥有的数据和变量只属于它自己。 线…

单线程与多线程的区别?

什么是进程&#xff1f; 当一个程序开始运行时&#xff0c;它就是一个进程&#xff0c;进程包括运行中的程序和程序所使用到的内存和系统资源。 而一个进程又是由多个线程所组成的。 什么是线程&#xff1f; 线程是程序中的一个执行流&#xff0c;每个线程都有自己的专有寄存器…

单线程与多线程

目录 多线程的创建 方式一&#xff1a;继承Thread类 方式二&#xff1a;实现Runnablel接口 方式三&#xff1a;JDK5.0新增Callable接口 Thread的常用方法 线程安全 线程同步 线程通信 线程池【重点】 定时器 补充知识&#xff1a;并发、并行 生命周期 什么是线程&…

什么是单线程和多线程,单线程与多线程的区别

什么是进程&#xff1f; 当一个程序开始运行时&#xff0c;它就是一个进程&#xff0c;进程包括运行中的程序和程序所使用到的内存和系统资源。 而一个进程又是由多个线程所组成的。 什么是线程&#xff1f; 线程是程序中的一个执行流&#xff0c;每个线程都有自己的专有寄存器…

理解单线程和多线程的区别

单线程和多线程 首先我们都知道线程是隶属于进程的,单线程就是程序中只有一个线程,多线程就是程序中有多个线程.通过连个例子理解多线程和单线程. (一)单线程 创建包:package com.ffyc.javathread; 创建类:public class Sample { } package com.ffyc.javathread; public c…

ubuntu卸载已安装软件

1.查看已安装软件列表 dpkg -l dpkg -l | grep baidu # 软件包查询筛选# 另外&#xff0c;软件安装也使用dpkg命令 sudo dpkg -i xxxx.deb2.卸载指定软件包 sudo apt-get purge baidunetdisk # 卸载指定软件 sudo apt-get autoremove # 清理不需要的文件 sudo apt-get autoc…

Ubuntu20.04 卸载软件

Ubuntu20.04卸载软件相当的简单&#xff0c; 一 用命令行卸载 sudo apt-get remove --purge 软件名 这样不仅可以卸载掉软件&#xff0c;而且可以清理配置 二 在图形界面卸载软件 首先打开设置 打开应用程序 在其中找到你要卸载的软件 然后点击右上角的 在软件中打开 然后…

Linux bash卸载软件,Ubuntu卸载软件的4种方法

前言 本文重点介绍Ubuntu卸载软件的4种方法。他们分别是图形化界面的synaptic、自动解决依赖关系的apt-get,处理依赖关系更强大的aptitude,还有安装本地deb包的dpkg。 方法一: Ubuntu使用synaptic图形化界面管理软件 oucanrong@zcwyou:~$ sudo apt-get install synaptic -y 以…