Linux开发工具gcc/g++篇

news2024/11/24 7:20:06

在这里插入图片描述

文章目录

  • 🍇0. 前言
  • 🍈1. 背景知识
  • 🍉2. gcc/g++使用
    • 🍊2.1 预处理操作
      • 🍋去注释
      • 🍋头文件展开
      • 🍋条件编译 & 宏展开
    • 🍊2.2 编译操作
    • 🍊2.3 汇编操作
    • 🍊2.4 链接
  • 🍍3. 库的介绍
    • 🍏3.1 动态库
    • 🍏3.2 静态库
    • 🍏3.3 动态库&静态库对比
  • 🥕4. gcc/g++选项
  • 🍒5. release & debug 介绍
  • 🍓6. sudo权限提升
  • 🥥结语

🍇0. 前言

Linux环境中,写好了C/C++的代码,要将其运行起来,我们采用的是gcc/g++ 这两个工具,gcc专门用来编译C语言的代码,g++专门用来编译C++的代码(C++兼容C语言,g++也可以用来编译C语言代码)。

image-20230604123210264

这个操作固然简单,但是gcc/g++是如何将这种源文件生成我们的可执行程序的呢?本篇文章将重点讲解这其中的过程。

🍈1. 背景知识

一个源文件要生成可执行文件,需要经过四个阶段:

  1. 预处理: 插入头文件内容,进行宏展开
  2. 编译: 源代码转换为汇编语言
  3. 汇编: 将汇编语言代码转换为机器语言指令
  4. 链接: 将多个目标文件和库文件组合在一起,生成最终的可执行文件

而gcc/g++可以根据需求,生成对应的文件。

Tips:

之前有篇文章讲过这些知识,在本篇文章中就不再过多赘述,想了解的可查看——被隐藏的过程

🍉2. gcc/g++使用

🍊2.1 预处理操作

指令示例:gcc -E code.c -o code.i

-E,该选项作用是让gcc在预处理结束之后,停止编译

-o,生成后的目标文件,一般采用i为后缀表示经过预处理的C原始程序。如果不跟-o,这直接将内容输出到屏幕上。

image-20230604133725334

预处理阶段主要进行四个处理:

  1. 去注释
  2. 头文件展开
  3. 条件编译
  4. 宏替换

🍋去注释

注释只是方便我们编写的人或者要查看这个代码的人知道这一块是用来干嘛的或者进行了哪些操作,而对于计算机,并不需要这些注释。

image-20230604133637976

🍋头文件展开

在Windows或者Linux环境下,要进行C/C++或者其他形式的开发,我们会安装配置对应的开发环境,这些是开发的前提。

以C/C++开发为例,开发环境不仅仅是VS、VsCode、gcc这些软件,更重要的是语言本身的头文件和库文件。

Linux默认为我们安装好了对应的环境

image-20230604130515862

在Windows上,安装Vs20xx时,在安装的时候我们还选择的对应的开发包,这些开发包里面就包含了其中的头文件和库文件。

image-20230604130550124

我们最开始学习C语言的时候,接触的第一行应该就是#include<stdio.h>,这就是把头文件包含进来,里面有我们需要使用的各种函数声明,在预处理阶段,就会将我们引用的头文件所展开:

image-20230604133521231

🍋条件编译 & 宏展开

条件编译根据当前宏定义的存在与否,决定了相应的代码块是否会被编译到最终的可执行文件中。通过条件编译,可以根据不同的条件选择性地编译不同的代码,以适应不同的编译环境或配置需求。

image-20230604135741425

这里我们发现,我们所定义的在预处理阶段直接被替换,而用于判断的宏条件,也进行了裁剪。

当然了gcc在预测阶段,既然可以去注释、展开头文件、宏替换,这就说明了gcc具有直接修改代码的能力,那我们在预处理的时候,也可也手动的修改:

image-20230604140358127

我们用的一些软件例如:Vs2022,分为社区版专业版

那么通过这个软件的公司,他们需要维护两份代码吗?

那当然不是,分开维护所需要的成本会大大提升,公司肯定不希望这样。

这时候条件编译就能起到作用:只需要维护专业版,然后在根据不同的编译条件,裁剪掉社区版不需要的功能即可。

🍊2.2 编译操作

指令示例:gcc -S code.c -o code.s

-S,将预处理之后的文件,翻译成汇编语言之后停止操作

一般以.s表示汇编代码文件

image-20230604141502666

汇编指令,是最底层的编程语言,我们可以具体查看这些代码是如何操作的。

image-20230604142149543

🍊2.3 汇编操作

指令示例:gcc -c code.c -o code.o

c,进行程序的翻译,汇编操作执行完毕之后就停止

汇编阶段是把编译阶段生成的.s(直接源文件转化也行)文件转成目标文件

目标文件是二进制表示,全称:可重定位二进制目标文件。Windows环境下后缀名为.obj

image-20230604143549571

🍊2.4 链接

指令示例:gcc code.o -o code

将目标文件与所需库文件进行关联,最终生成可执行程序

image-20230604143918036

指令文件后缀
-E.i预处理之后
-S.s编译之后
c.o汇编之后

🍍3. 库的介绍

我们所写的代码printf,scanf类似这些函数,都是由库来进行实现,而链接阶段就是链接的这些库。

对应C语言就是链接的C标准库

image-20230604194405788

这个库本质上就是一个文件,由于环境的不同,库有各种格式:

Linux:.so(动态库),.a(静态库)

Windows:.dll(动态库),.lib(静态库)

这个库有自己的命名规则:libname.so.XXX,我们在看这个库的时候,只需要看这中间的一块就行。

在服务器上,默认只有动态库,静态库默认是没有安装的。

这也对应上面讲的,我们进行开之前安装的开发包,下载安装的就是对应的头文件库文件

在库文件中有我们需要使用的各种函数的实现,这些函数的实现,也是由程序员写的,只不过都打包到库文件中,这样我们在使用的时候就不需要到处去找,不需要我们自己去“造轮子”;另一个方面,这样也可以达到隐藏源文件的目的,用可以,怎么造出来的,保密。

这样整体流程下来就是:

头文件提供方法的声明、库文件提供方法的实现 + 自己写的代码 = 最终的可执行文件

库的链接分为静态链接动态链接

🍏3.1 动态库

打一个直白的比方:

大学里面一般有实操课,以计算机专业的为例。

假如今天上午没课,下午有一下午的上机课,知道了今天的课程安排,那我们就可以列一个今天的计划:

洗澡->洗衣服->打扫卫生->看一部电影->点个外卖吃饭->上机课->回宿舍打游戏…

这些计划里面,除了上机课要出宿舍楼,其他的都可以在宿舍里面进行。

那么这里的去机房这个行为,就类似于动态库,而我们就相当于可执行程序,当我们发现上机课,这个行为无法在宿舍完成时,我们就得机房,这就是程序跳转到库中执行,执行完毕之后,返回代码调用处,在继续完成之后的命令。

那我们是如何知道机房在哪儿呢?我们可以提供查看课表得知,这个过程就相当于编译器,在我们的大脑中注册了这个“信息”。

这个机房当然不只是属于我自己或者是我们班,这个是全校有上机课安排的学生共享使用的,所以这个动态库一般也被称为共享库

如果这个动态库消失,那么将会导致很多程序都无法运行。

image-20230604202802401

如图我们可以发现,不仅仅是我们自己写的程序依赖库,而且Linux里面的一些指令,也是依赖于C语言的库,这是因为Linux的底层就是用C语言实现的。

🍏3.2 静态库

接着上面的比方:

如果机房维修或者我们平时用到电脑情况较多,那我们需要有自己的电脑,这样我们就会有买电脑的需求,我们从商家那里购买电脑,从而达到操作电脑的目的。这个过程商家就好比是静态库,我们从他那里买了电脑,将电脑放在自己的桌子上,从而我们能够操作电脑,这就是静态链接。就算这个商家倒闭了,也不影响我们继续使用。但这样也占据了我们宿舍的一部分实际空间。

在编译器调用静态库进行静态链接的时候,会将静态库中的方法直接拷贝到目标程序中,该程序就不再依赖静态库了,但随之程序的内存也变大了

🍏3.3 动态库&静态库对比

在Linux中,编译形成的可执行程序,默认采用的是动态链接,如果需要采用静态链接,则需要我们手动进行。

示例:gcc code.c -o code-static -static,后面加上-static就是提示系统进行静态链接。

image-20230604205558469

Tips:

服务器默认是没有安装静态库的,我们需要手动安装:

C语言静态库:sudo yum install -y glibc-static

C++静态库:sudo yum install -y libstdc++-static

这里普通用户安装需要权限提升,文章末尾有说明

如果我们没有静态库,是无法进行静态链接的;

如果没有动态库,只有静态库,gcc也是可以找到的,只是gcc默认优先寻找动态库。这里也变相说明了-static的本质是改变寻找的优先级,但是这只适配一次,意思就是如果没有对应的静态库,则报错。

计算机专业的学生,可能平时玩的比较欢快,但是到期末的时候,要交结课作业了,可能是一个xx系统,这时候就慌了,于是就去各种开源网站上面找啊找啊找啊,好不容易找到一个,拿来一用,发现报错栏通红通红的。然后编译器可能就提示缺少什么什么东西,要下载,下载的这些东西里面就包含了一些动态库。好啦,下载完毕了,一运行发现还是有一堆通红的报错,这可能就是缺少了静态库(报错并不一定仅仅是由于缺少动态库或静态库引起的。还可能存在其他问题,例如代码本身的错误、版本不兼容、编译选项配置不正确等,我这里仅仅是举例)。

这就说明了,我们的一些程序,不一定全部是动态链接或者静态链接,可能是混合的。

提供这些了解,我们就可知道一些动态库和静态库的优缺点:

  • 动态库:

    优点:共享库,节省资源

    缺点:一旦缺省,会导致许多程序无法运行

  • 静态库:

    优点:不依赖库,程序可独立运行

    缺点:体积大,消耗资源较大

🥕4. gcc/g++选项

选项说明
-c仅编译源文件,生成目标文件(.o文件),不进行链接操作。
-o <file>指定生成的可执行文件的名称。
-g包含调试信息,以便进行源代码级别的调试。
-Wall启用所有警告信息。
-Werror将警告视为错误,导致编译失败。
-O<level>启用优化级别。
-std=<standard>指定使用的语言标准。
-I<dir>添加包含文件的搜索路径。
-L<dir>添加库文件的搜索路径。
-l<library>链接指定的库。
-D<macro>定义预处理宏。
-U<macro>取消定义预处理宏。

这只是一些常见的选项示例,gcc和g++支持的选项非常多,可以根据需要查看官方文档以获取更详细的信息。可以使用gcc --helpg++ --help命令查看完整的选项列表和说明。

🍒5. release & debug 介绍

我们写的程序一般分为两个版本:releasedebug

  • release:

    发布版本,无法调试,编译器会进行各种优化,以提高程序的性能和效率。使用Release配置编译生成的可执行程序通常会具有较高的性能和较小的体积。但由于优化的关系,对于调试和错误定位可能不太友好,因为很多调试信息被削减或省略。

  • debug:

    用于开发和调试阶段的版本,使用Debug配置编译生成的可执行程序可能会比较慢,并且占用更多的存储空间。但它们提供了更多的调试信息,使得在开发和调试过程中能够更方便地定位和修复问题。

gcc默认的是release版本,可使用指令gcc code.c -o code_debug -d生成debug版本:

image-20230604224309320

🍓6. sudo权限提升

当普通用户想要执行一些操作时(例如下载一些软件),权限不够,这时候就需要进行权限提升。

sudo指令就能将用户权限暂时提升。

image-20230604112128590

我们发现,当我们使用sudo提升权限的时候,被拒绝了,原因是我们没有被添加进信任白名单。这个操作是需要root用户来进行添加的。

image-20230604112817909

切换成root用户,然后用vim编辑器进入这个文件vim /etc/sudoers

image-20230604113143230

大概在100行左右(如果没有行号,指令: set nu,尽量不要使用鼠标滚动,vim有自己的上下键),就能看到我们的信任白名单。

复制粘贴root这一行,然后再更改用户名即可。因为这个文件只有读权限,所以在最后退出到时候,强制写入保存退出: wq!

image-20230604114039209

这时候我们就可以进行权限提升了:

image-20230604114315810

当然了,如果这个用户提升权限之后喜欢搞破坏,root用户也是有权限将其从白名单剔除的。

就算将root从这个白名单剔除,root也还是不受约束,因为root就是Linux中的最高权限。

image-20230604114937901

🥥结语

本篇文章基本上是已C语言为例,采用的是gcc;对应C++的编译工具g++是同理直接用就行。另外除了介绍gcc/g++的使用,还提到了一个程序是如何从源代码最终生成可执行文件的皮毛内容,如果大家有兴趣,可以去查阅书籍了解这其中的详细过程。

那么本次的分享就到这里啦,如果有帮助的话希望三连支持一下,我们下期再见,如果还有下期的话。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/610162.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python多段分段函数的介绍

Python多段分段函数的介绍 在Python编程中&#xff0c;有许多种不同类型的函数&#xff0c;其中之一是多段分段函数。多段分段函数的特点在于&#xff0c;在输入域上&#xff0c;函数定义被划分为不同的段&#xff0c;每个段都求值并返回结果。在本文中&#xff0c;我们将深入…

Java性能权威指南-总结5

Java性能权威指南-总结5 垃圾收集入门垃圾收集概述分代垃圾收集器 垃圾收集入门 很多时候没有机会重写代码&#xff0c;又面临需要提高Java应用性能的压力&#xff0c;这种情况下对垃圾收集器的调优就变得至关重要。 现代JVM的类型繁多&#xff0c;最主流的四个垃圾收集器分别…

使用RP2040自制的树莓派pico—— [2/100] HelloWorld! 和 点亮LED

使用RP2040自制的树莓派pico—— [2/100] HelloWorld! 和 点亮LED 开发环境HelloWorld!闪烁 LED 灯代码 由于比较简单就放在一起写了 开发环境 软件&#xff1a;Thonny HelloWorld! 要想使串口打印HelloWorld&#xff01; 只需要一行代码 print("HelloWorld!")保…

c++与c中多组输入的使用

我们现在看看c中多组输入的使用 int main() {int a;//1while (~scanf("%d", &a)){}//2while (scanf("%d", &a) ! EOF){}return 0; } 这两个是等同的 我们需要知道的是scanf的返回值是成功读取的个数&#xff0c;我们来验证一下 我们可以看到&am…

chatgpt赋能python:Python在Mac上的运行方法

Python在Mac上的运行方法 如果你是一名使用Mac系统的Python开发人员&#xff0c;你肯定希望能够尽可能方便地运行Python。幸运的是&#xff0c;Mac系统已经预先安装了Python&#xff0c;但是你可能需要对其进行配置&#xff0c;以便更好地管理Python模块和环境。 检查Python版…

chatgpt赋能python:Python地区分析:如何使用Python进行地理数据分析

Python地区分析&#xff1a;如何使用Python进行地理数据分析 简介 Python是一种广泛使用的编程语言&#xff0c;它提供了许多强大的工具来处理大量数据。其中包括地理数据&#xff0c;地理数据是指地球表面的空间信息。Python中有一些强大的地图库&#xff0c;包括Folium和Ba…

chatgpt赋能python:Python的均值计算公式

Python的均值计算公式 在数据分析和机器学习方面&#xff0c;计算均值是非常常见的操作。Python提供了一些内置函数和库来计算均值。本文将介绍Python中常用的均值计算公式。 1. 算术均值 算术均值&#xff08;Arithmetic Mean&#xff09;是最常见的均值计算方法。Python中…

解决高并发

目录 1.4 对比单体系统、分布式系统和微服务系统 1.4.1 单体系统之痛 1、什么是单体系统 2、单体系统面临的问题 1.4.2 高并发系统之分布式架构 1.4.3 高并发系统之微服务架构 1.4 对比单体系统、分布式系统和微服务系统 接下来从企业真实场景出发&#xff0c;对比单体系统…

ROS:服务端Server的编程实现

目录 一、服务模型二、创建功能包三、创建代码并编译运行&#xff08;C&#xff09;3.1步骤3.2创建服务端Server代码3.3编译3.4运行 一、服务模型 Server端本身是进行模拟海龟运动的命令端&#xff0c;它的实现是通过给海龟发送速度&#xff08;Twist&#xff09;的指令&#x…

【Android Framework系列】第1章 Handler消息传递机制

1 Handler简介 Handler是一套Android的消息传递机制&#xff0c;Handler主要用于同进程的线程间通信。而Binder/Socket用于进程间通信。 2 Handler运行机制 Handler运行主要涉及到四个类&#xff1a;Handler、Looper、Message、MessageQueue Handler&#xff1a;消息处理器&…

chatgpt赋能python:Python文件备份的重要性和应用

Python文件备份的重要性和应用 在现代企业和个人用户中&#xff0c;数据备份是一项至关重要的工作&#xff0c;以防止数据丢失或损坏。当涉及到计算机数据时&#xff0c;文件备份是一项基本需求。文件备份还可以用于保护文件&#xff0c;以防它们被病毒、恶意软件或未经授权的…

法规标准-UN R158标准解读

UN R158是做什么的&#xff1f; UN R158全名为针对驾驶员识别车辆后方弱势道路使用者&#xff0c;联合国对倒车系统和机动车的统一规定&#xff0c;该法规涉及批准倒车和机动车辆的装置&#xff0c;主要为保证倒车时避免碰撞&#xff0c;方便驾驶员观察了解车辆后部人员和物体…

dSPACE一览(暂存)

1. SCALEXIO - dSPACE 2. dSPACE仿真流程介绍&#xff08;dSPACE软件介绍、仿真演示、自动化API接口使用&#xff09;_云溪溪儿的博客-CSDN博客 目录 硬件 板卡 软件 VEOS 应用领域 全面总线仿真 高效集成多种建模方法 硬件 板卡 SCALEXIO FPGA Subsystems DS6601 FPG…

STM32通过esp8266连接WiFi接入MQTT服务器

上文我们讲到如何搭建本地MQTT服务器&#xff0c;现在介绍如何通过stm32连接MQTT 一.首先我们初始化esp8266这里我们使用的是USART4与其通信代码如下 void UART4_Init(uint32_t bound) {GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;RCC_APB1…

高通 Camera HAL3:添加一条PipeLine

一.概述 添加一条PipeLine实现两路Raw进&#xff0c;一路Raw出 二.简介 要添加的PipeLine&#xff1a;SWMFMergeRawTwo2One 包含1个memcpy node&#xff0c;这个node用于将2个raw buffer input输入 变为 1个raw buffer output输出 三.添加 3.1 在相应的Usecase下添加一个p…

Spring Cloud Alibaba - Nacos源码分析(一)

目录 一、源码 1、为什么要分析源码 2、看源码的方法 二、Nacos服务注册与发现源码剖析 1、Nacos核心功能点 2、Nacos服务端/客户端原理 2.1、nacos-example 2.2、Nacos-Client测试类 3、项目中实例客户端注册 一、源码 1、为什么要分析源码 1. 提升技术功底&#x…

NB使用MQTT连接格物平台

内容简介&#xff1a; 本文主要记述了怎么使用NB-IoT模块&#xff0c;采用MQTT协议连接联通的格物平台&#xff0c;并且实现单属性和多属性数据的上报。 1 创建产品 打开格物平台&#xff0c;进行注册登录&#xff1b;之后点击页面的控制台&#xff0c;进入设备管理引擎&#x…

爬取中文新闻+正向、逆向最大匹配算法分词+算法优化+P、R、F值评估(完整详细过程+Python源码)

如标题所示&#xff0c;本文旨在记录这次分词实验&#xff0c;将主要从以下四点展开&#xff1a; 1、新闻文本的获取&#xff08;完整爬虫过程&#xff09; 爬取新闻网站中多个板块的新闻&#xff0c;这里建议可以多爬一些板块&#xff0c;保证新闻内容主题丰富&#xff0c;分…

计算机网络 - 移动网络

Wireless links and network Characterstics 无线网络信号会衰减很快, 会被别的source影响, 传播过程中经历多个路径比如经过建筑, 树木等收到影响. 所以就有了信噪比的概念 CDMA CDMA是一种在多点连接时候避免collision的一种算法. 主要是每个sender都用不同的编码, 然后se…

chatgpt赋能python:Python声音处理入门指南

Python声音处理入门指南 如果你是一个音乐爱好者或者处理声音的工程师&#xff0c;Python语言是值得你考虑的一种工具&#xff0c;它拥有丰富的库&#xff0c;可以帮助你在声音分析、编辑、压缩和转换等方面做出成果。 Python声音处理库 Python语言拥有一个大量的声音处理库…