【Linux】gcc编译器

article/2025/10/2 15:57:37

目录

一、什么是编译器

二、编译的过程

1.预处理

2.编译

3.汇编

4.链接

三、实际操作实例

四、总结


一、什么是编译器

      简单讲,编译器就是将一种语言转化为另一种语言的程序,通常是将高级语言转化为低级语言。一个现代编译器的主要工工作流程:预处理 →编译 →汇编 →链接 ,最终生成可执行程序

      高级计算机语言便于人编写,阅读交流,维护。而机器语言是计算机能直接解读、运行的。编译器将汇编或高级计算机语言源程序作为输入,翻译成目标语言机器代码的等价程序。源代码一般为高级语言, 如C、C++、JAVA等,或者汇编语言,而目标代码则是机器语言的目标代码,也称机器代码。

       gcc/g++是C语言和C++语言代码的编译器,因为C++兼容C,所以g++编译器也可以编译C语言代码。本文主要讲述的是gcc编译器的操作和功能。

二、编译的过程

利用gcc编译器一步到位生成可执行文件的命令是:

gcc -o myfile myfile.c 或者 gcc myfile.c -o myfile。

其中的选项-o和生成的可执行文件myfile必须相邻。上述命令是对myfile.c文件进行编译生成可执行文件myfile。

1.预处理

预处理阶段会对程序进行头文件展开、条件编译、宏替换、去注释等操作。生成的文件后缀为 .i

-E                     从现在开始对文件进行编译,预处理结束后停止操作。

命令为:gcc -E myfile.c -o myfile.i

同理,其中的选项-o和生成的文件myfile.i必须相邻。

注:

1.头文件展开:

①#include指令使另外一个文件被编译:预处理器先删除这条指令,并用包含文件的内容替换。这样一个文件被包含10次,那就实际被编译10次。文件开头写:#pragma once 可以避免头文件的重复引入。

②库文件一般用 < > 包含;本地文件一般用 “ ” 包含。

2.条件编译:

①#if 指令用于检测后面的常量表达式,如果为真,则编译接下来的代码,直到出现 #else、#elif、#endif为止;否则就不编译。

②#ifdef指令用于检测后面的表达式,如果被定义,编译接下来的代码;#ifndef指令用于检测后面的表达式,如果未被定义,编译接下来的代码。

③#endif 指令用于终止#if,#ifdef,#ifndef和预处理指令。

3.宏替换:

宏定义中可以出现其他宏定义的符号,但是不能出现递归。

在定义宏时,经常会出现的两个运算符 # 和 ##

#:出现在宏定义中的#运算符,会将其后面参数转化为一个字符串。我们把这种用法的成为字符串化运算符。

##:常用于把多个参数连接在一起。

①在调用宏时,首先对参数进行检查,看看是否包含了任何由#define定义的符号。如果是它们首先被替换。

②替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替代。

③最后,再次对文本结果进行扫描,看看是否包含了任何由#define定义的符号。如果是就重复上述处理过程。

4.去注释:把源代码的注释部分全部删除。

2.编译

编译阶段会对程序进行语义语法纠错、将.c文件编译成汇编语言。生成的文件后缀为 .s

-S                    从现在开始对文件进行编译,编译结束后停止操作。

命令为:gcc -S myfile.i -o myfile.s

同理,其中的选项-o和生成的文件myfile.s必须相邻。

注:汇编语言与机器语言一一对应,是高级语言转化为机器语言的“中间人”。

3.汇编

汇编阶段进行将汇编语言变成二进制机器语言,生成可重定位目标二进制文件bin.obj,不可执行,后缀为 .o

-c                     从现在开始对文件进行编译,汇编结束后停止操作。

命令为:gcc -c myfile.s -o myfile.o

同理,其中的选项-o和生成的文件myfile.o必须相邻。

注:汇编阶段是对自己编写的代码转化成汇编语言后进行转换得到的目标二进制文件,还未与高级语言的库进行连接和转换,生成的目标文件是不可执行的。

4.链接

链接阶段将所有的目标文件和依赖的库文件进行汇总,得到最终的可执行程序。

与一次编译完是同一个命令,不需要额外的选项。

命令为:gcc  myfile.o -o myfile

同理,其中的选项-o和生成的文件myfile必须相邻。

那么,为什么gcc能进行C语言代码的编译并生成可执行文件呢?

因为,Linux系统默认携带了语言级别的头文件和语言对应的库

库分为两种——动态库(专门让编译器与用户的程序进行动态链接的)和静态库(专门让编译器与用户的程序进行静态链接的)。

静态库和静态链接:程序链接时如果是静态链接,则链接的库是静态库,链接的方式是通过                                  拷贝库文件中所需要的代码至二进制文件,链接成功后程序的执行不依                                  赖静态库,但多个程序执行拷贝相同的代码会带来空间的浪费。

动态库和动态链接:程序链接时如果是动态链接,则链接的库是动态库,链接的方法是拷贝                                  库文件中所需要代码的地址至二进制文件,链接成功后程序的执行依赖                                  动态库,若动态库被删除,则程序无法执行。

动态库和静态库的比较:动态库被链接时,代码的内容并没有被拷贝,而拷贝的是相关代码                                          的地址,较静态库而言节省空间,也避免了代码重复拷贝带来的不                                          必要空间浪费。Linux系统默认链接的是动态库

动态库的名称默认格式:libxxxx.so

静态库的名称默认格式:libxxxxx.a

(lib是前缀,.so和.a是后缀,xxxxx是库的名字

对于编译生成的可执行文件,可以通过命令“ldd 文件名”来查看是文件编译时的链接是动态链接还是静态链接。

 上图所示,test的链接方式是动态链接,链接的是动态库。

因为Linux系统默认链接的是动态库,想要进行静态链接,则需要增加一个-static的选项在命令的后面,整体的命令为gcc test.o -o test.static -static ,

(一般的云服务器,默认只有动态库,如果你想要进行静态链接,可以通过yum命令:yum install glibc-static libstdc++-static -y安装静态库 。)

三、实际操作实例

1.创建C程序文件test.c并用vim进行编写,保存后查看test.c的文件内容:

2.输入命令,进行文件的预处理,生成后缀为 .i 的文件test.i

3.输入命令,进行文件的编译操作,生成汇编文件test.s

4.输入命令,将汇编语言转换成二进制机器语言,生成二进制重定向文件test.o

5. 输入命令,将二进制文件和库文件进行合并,生成可执行文件test

6.用"ldd test"命令查看可执行文件test是否是动态链接

由上图可知,可执行文件test是动态链接的,链接的库是动态库(又称共享库)

7.通过命令gcc test.o -o test.static -static或者gcc test.c -o test.static -static来生成静态链接的可执行文件test.static

(注:上面对动态链接和静态链接的举例皆是借助该实例进行说明的)

四、总结

  本文主要讲述了gcc编译器编译代码的基本过程,以及链接时链接的库文件的属性分类及对应的链接方法。gcc是Linux系统下的C语言编译器,可以执行我们编辑的C语言代码,但如果涉及到多文件(即项目文件需要多个.c文件)时,像上述的方法进行编译会很麻烦,那应该如何解决呢?下篇文章将会进行相关工具——make和Makefile的讲解,欢迎大家垂阅。


http://chatgpt.dhexx.cn/article/7RntR4M3.shtml

相关文章

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 以…

Ubuntu卸载软件方式

1、终端输入&#xff1a; dpkg --list 显示出电脑上所有的软件包 左边就是软件名字&#xff0c;中间是版本名 2、在终端上输入命令sudo apt --purge remove 包名 例如我要卸载smartgit 即可