一文入门gcc

2024-06-15 23:20
文章标签 gcc 入门 一文

本文主要是介绍一文入门gcc,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天我们来玩玩gcc。

是因为突然发现ESP-IDF用的是CMake,要了解CMake最好就要先学习Makefile有个基础,学习Makefile最好就要先熟悉gcc,所以就有了今天这篇文章。

首先我们要明确一个问题,那就是gcc/g++是什么,它们有什么用。

gcc 是 GNU Compiler Collection(GNU 编译器集合)的缩写,是一个用于编程语言的编译器,特别是 C、C++、Fortran、Objective-C、Objective-C++、Ada、Go 以及其他一些语言。它最初是为 GNU 操作系统开发的,但如今已被广泛应用于各种 Unix-like 系统(包括 Linux)和其他操作系统(如 Windows,通过 MinGW 或 Cygwin)。

gcc 的主要用途是将源代码(例如 C 或 C++ 代码)编译成机器代码(通常是可执行文件或库)。它支持多种优化选项和调试选项,使得开发人员能够根据需要调整编译过程。

简单来说gcc就是编译器,它可以将我们写的.c文件变成.exe的可执行文件(当然了,不止.c文件,可执行文件的后缀也不一定是.exe)。

而g++也属于gcc,不过是专门为了编译C++而产生的特化版本。

由于大家初学C语言的时候,大概率是看着教学视频学的,并且视频里一般都是教大家下载IDE,在IDE里进行编程的,因此我们不需要去关注具体是如何使用编译器去编译我们的c文件的。但是到了Linux环境下,就没有那么轻松了(虽然Linux也可以下载安装IDE,但是很多情况下我们用的不是有图形界面的Linux,而是命令行,这样也比较帅对叭),我们需要手动敲命令去对我们写好的程序进行编译。

安装gcc

那么第一步,我们需要先安装上gcc。

我们打开虚拟机,或者你有服务器可以远程连接上也可以,再或者你远程连接你的虚拟机也OK。

我这边以Ubuntu为例(因为手头上安装的虚拟机是Ubuntu的)

我们在命令行里输入下面这个命令

sudo apt-get install gcc

如果成功下载,那么我们可以直接进入下一步。

如果下载不了,显示没有这个软件包,那么我们需要加个源。

执行下面的命令去修改源列表文件。

vim /etc/apt/sources.list

添加一行下面这个内容(不会用vim的小伙伴在上面那个命令执行过后按下i键,然后用上下左右键移动到文件的最下面,然后将下面的复制进去,接着按下esc键,再打个 :冒号,然后输入qw保存退出,如果显示权限不够那就出去改个权限。)。

deb [arch=amd64] http://archive.ubuntu.com/ubuntu focal main universe

下一步更新源。

sudo apt-get update

更新完之后下载gcc。

sudo apt-get install gcc

再输入下面命令查看gcc版本,如果能正常看到那么就表示我们下载成功。下载g++的话只需要把上面下载命令中的gcc替换成g++即可。

gcc -v

编译的流程

接下来我们来了解一下.c文件是如何变成.exe文件的。

一共是四个步骤,分别是预处理,汇编,编译,链接。曾经VS帮我们做好了一切,如今我们需要还我们欠下的债了,深刻理解这四个步骤也有助于我们理解我们自己写下的代码(没错,就算是你自己写的代码你也不一定能够彻底明白,反正我上星期写的代码我这星期已经看不懂了)。

预处理

预处理这一步主要会做下面这些步骤。

  • 代码包含:预处理器处理#include指令,这通常意味着将头文件的内容直接插入到源文件中。
  • 宏替换:所有#define定义的宏都会被展开,即在代码中进行相应的文本替换。
  • 条件编译:处理如#if#ifdef等条件编译指令,这些指令通常用于在不同环境下编译不同的代码路径。
  • 注释删除:预处理器会移除所有注释部分,这些注释对编译后的代码执行没有影响。
  • 生成中间文件:预处理过程后通常会生成一个中间文件(如.i文件),供后续编译过程使用

在gcc中预处理的选项是-E,我们只需要使用gcc -E 这个命令就可以对我们写的.c文件进行预处理了。但是光预处理还没有,我们需要把预处理的结果保存起来,这时候就需要使用-o选项来指定文明存放预处理结果的文件。

使用例子如下。其中test.c是写的.c文件,test.i是预处理结果

 gcc -E test.c -o test.i

然后test.c的内容是下面这样的。

很简单的内容,包含了个头文件,使用宏定义代替了一个打印语句。在main函数里使用宏定义并且用了个打印语句。

经过预编译之后我们得到test.i文件。实际上可以叫任何名字,只需要在上面预编译的命令中修改即可,甚至后缀都不一定非得是 .i ,在Linux中后缀是没有实际作用的,它唯一的作用是对于让人可以通过后缀判断出这个文件是什么类型的,而对于Linux来说,后缀是无所谓有无所谓无的东西。

虽然名字可以随意,但是我们约定俗成的命名规则就是保留.c文件的名字,然后修改后缀。

接着我们看看预处理后得到的test.i是什么内容。

原本很简单的一段代码,经过预处理之后变成八百多行了。

文件开头我们看不懂,我们拉到最下面。

主要看最后面的main函数,里面的宏定义被替换成了printf语句。并且注释也没有了。还将我们的头文件展开了,没错,前面差不多八百行代码就是原文件中的#include <stdio.h>展开后的结果。

这就是预处理。

编译

编译这个步骤会对上个步骤得到的 .i 文件做以下处理,最终生成汇编文件。

  • 词法分析:编译器首先识别出源代码中的每个单词,如变量名、运算符等。
  • 语法分析:之后,编译器解析这些单词组成的语法结构,如表达式、控制结构等。
  • 语义分析:确保所有变量都被正确声明,且操作都是合理的,例如类型检查。
  • 优化:编译器会对中间代码进行优化,以提升执行效率,去除不必要的操作。
  • 生成汇编代码:最终,编译器生成对应的汇编代码文件(如.s文件),此代码是机器语言的低级表示。

gcc中汇编的选项是 -S ,得到的汇编文件的后缀一般我们都给 .s ,所以使用的命令如下。

gcc -S test.i -o test.s

我们可以来查看一下生成的汇编文件。

虽然还是很多,但是已经压缩成48行了。汇编就已经是很接近底层的了。

汇编

  • 代码翻译:汇编器将汇编代码转换成机器码,生成目标文件(如.o文件)。
  • 符号引用解决:这一阶段还会处理代码中的符号引用,确定所有引用的目标地址。

下一步就是汇编了,这有点小迷惑人,因为编译的结果是汇编文件,而汇编的结果是目标文件。

gcc中执行汇编步骤的选项是 -c ,示例命令如下。

gcc -c test.s -o test.o

输入的是 .s 文件,输出的是 .o文件。这一步就将我们的汇编转成机器码了,当我们再去查看的时候就不是我们能够看懂的了(虽然我估计大部分人连汇编都看不懂了(包括我))。

还有个需要说的,就是汇编这一步,可以直接从 .c到 .o,也就是可以跳过前两步直接到第三步。 

链接

最后一步链接,就可以生成可执行文件了。

  • 合并代码:链接器将所有的目标文件以及它们所需要的库文件合并,形成最终的可执行文件。
  • 解析外部引用:解决不同文件之间相互调用的函数或者变量地址解析问题。
  • 生成可执行文件:最终输出一个可执行的程序文件,该文件可以直接在操作系统上运行。

gcc中链接这一步骤不需要选项,也就是像下面这样。

gcc test.o -o test

直接输出没有后缀的可执行文件(可以让它的后缀为exe方便理解,但是在Linux中我们一般直接不要后缀)

那么我们就已经有了一个可执行文件了,应该怎么执行呢?

./test 

像上面这样一个点加个斜杠再加上可执行文件的名字就可以啦。

结果是下面这样的。

可能有小伙伴会说这个gcc也太麻烦了,我还是用IDE吧。

那其实我们要可执行文件的话可以不用按照这四个步骤一步步来,现实中我们不能一步登天,但是在gcc里可以,我们可以直接执行下面这个命令,直接从 .c 编译成可执行文件。

gcc test.c -o test

这样就简单很多了。

上面就是gcc最基本的用法了,懂得上面这几步之后,理论上去学个Makefile什么的问题不大。

不过我们可以再深入了解了解gcc,这个拥有着强大功能的工具不可能就做这么点事对吧。

指定头文件目录

假如我们现在写了一个含有功能函数的文件(或者是下载来的),那么我们在主函数要用对应的函数,那么就需要包含头文件对吧。

现在我在main.c文件的同级目录下专门建了个文件夹存放工具文件。并且我在main.c里包含了这些文件。像下面这样。

然后我们再编译就会发现gcc找不到我们的头文件。

这时候就要请出我们gcc指定头文件的选项 -I 了。

gcc -I ./my_tools test.c -o test

这样包含头文件就没问题了,但是又出了新的问题,那就是找不到函数定义了。

这是因为我们需要把被包含的文件一起放进来编译。

这样就没问题了,可是这样子写的话会非常麻烦,光是包含一个头文件就要加这一长串,万一我包含了很多呢?这就要请出我们的Makefile了(下一篇也可能是下n篇文章我们再说)。

总之我们先知道指定头文件目录的这个选项即可。

设置优化级

-O选项可以设置优化级,这边是大写的O,别和之前小写的o混一起了。

GCC编译器提供了多种优化级别,通过使用-O后跟一个数字(从0到3),可以指定希望GCC应用的优化等级。

  1. 优化级别0 (-O0)

    • 关闭所有编译优化。这是默认的编译设置,主要用于调试阶段,因为优化可能会改变程序的执行方式,从而影响调试的准确性。
  2. 优化级别1 (-O1)

    • 开启基本优化。这一级别的优化包括将常用值分配给寄存器、消除无用的代码等简单优化。这是在不影响调试的前提下提高程序性能的一个平衡选择。
  3. 优化级别2 (-O2)

    • 开启中级优化。除了包含-O1中的所有优化外,还包括了更复杂的优化如分支预测、循环展开、内联函数等。这可以显著提高程序的运行速度,但可能会增加编译时间和最终可执行文件的大小。
  4. 优化级别3 (-O3)

    • 开启高级优化。它包括-O2中的所有优化,并尝试进一步执行如函数内联扩展等更高级的优化技术。此级别适用于当程序性能是关键考虑因素时,但需要注意这可能会使编译时间变长,并且在某些情况下可能影响程序的稳定性或可预测性。
  5. 额外优化级别 (-Os)

    • -Os:专注于生成尽可能小的可执行文件大小。适用于嵌入式系统和那些对程序大小有严格要求的场景。

默认的优化级别是O0,一般情况下我们不动它的。

添加宏定义

这个会用的多一点。

-D后接我们要在编译时候注册的宏。

我现在修改一下我们之前的test.c文件。

然后我们直接编译,运行的结果是这样的。

当我们使用了-D选项,则是下面这样的效果。

通过这样的小例子,相信大家就对-D有了简单的认识了。

今天在这边就介绍到这边了,对于我们后续学习Makefile来说是足够的。

感觉不过瘾,想更深入了解gcc的小伙伴可以直接

man gcc

也可以去查官方文档。

GCC online documentation- GNU Projecticon-default.png?t=N7T8https://gcc.gnu.org/onlinedocs/

这篇关于一文入门gcc的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1064868

相关文章

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

【服务器运维】CentOS7 minimal 离线安装 gcc perl vmware-tools

0. 本机在有网的情况下,下载CentOS镜像 https://www.centos.org/download/ 1. 取出rpm 有的情况可能不需要net-tools,但是如果出现跟ifconfig相关的错误,就把它安装上。另外如果不想升级内核版本的话,就找对应内核版本的rpm版本安装 perl-Time-Local-1.2300-2.el7.noarch.rpmperl-Tim

ps基础入门

1.基础      1.1新建文件      1.2创建指定形状      1.4移动工具          1.41移动画布中的任意元素          1.42移动画布          1.43修改画布大小          1.44修改图像大小      1.5框选工具      1.6矩形工具      1.7图层          1.71图层颜色修改          1

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使

LVGL快速入门笔记

目录 一、基础知识 1. 基础对象(lv_obj) 2. 基础对象的大小(size) 3. 基础对象的位置(position) 3.1 直接设置方式 3.2 参照父对象对齐 3.3 获取位置 4. 基础对象的盒子模型(border-box) 5. 基础对象的样式(styles) 5.1 样式的状态和部分 5.1.1 对象可以处于以下状态States的组合: 5.1.2 对象

装gcc

下载https://anaconda.org/serge-sans-paille/gcc_49/files  需要的gcc版本 把它放到/export/xxx/conda/pkgs 下 source要装的那个环境 到/export/xxx/conda/pkgs 下执行:conda install --use-local gcc_49-4.9.1-6.tar.bz2 装好后,gcc -v 发

C语言入门系列:探秘二级指针与多级指针的奇妙世界

文章目录 一,指针的回忆杀1,指针的概念2,指针的声明和赋值3,指针的使用3.1 直接给指针变量赋值3.2 通过*运算符读写指针指向的内存3.2.1 读3.2.2 写 二,二级指针详解1,定义2,示例说明3,二级指针与一级指针、普通变量的关系3.1,与一级指针的关系3.2,与普通变量的关系,示例说明 4,二级指针的常见用途5,二级指针扩展到多级指针 小结 C语言的学习之旅中,二级

打造坚固的SSH防护网:端口敲门入门指南

欢迎来到我的博客,代码的世界里,每一行都是一个故事 🎏:你只管努力,剩下的交给时间 🏠 :小破站 打造坚固的SSH防护网:端口敲门入门指南 前言什么是端口敲门端口敲门的优点1. 增强安全性2. 动态防火墙规则3. 隐匿服务4. 改善日志管理5. 灵活性和兼容性6. 低资源消耗7. 防御暴力破解和扫描8. 便于合法用户访问9. 适用于不同类型的服务 端口敲

好书推荐《深度学习入门 基于Python的理论与实现》

如果你对Python有一定的了解,想对深度学习的基本概念和工作原理有一个透彻的理解,想利用Python编写出简单的深度学习程序,那么这本书绝对是最佳的入门教程,理由如下:     (1)撰写者是一名日本普通的AI工作者,主要记录了他在深度学习中的笔记,这本书站在学习者的角度考虑,秉承“解剖”深度学习的底层技术,不使用任何现有的深度学习框架、尽可能仅使用基本的数学知识和Python库。从零创建一个