当前位置: 首页 > news >正文

【Linux系统】—— 编译器 gcc/g++ 的使用

【Linux系统】—— 编译器 gcc/g++ 的使用

  • 1 用 gcc 直接编译
  • 2 翻译环境
    • 2.1 预处理(进行宏替换)
    • 2.2 编译(生成汇编)
    • 2.3 汇编(生成机器可识别代码)
    • 2.4 链接
    • 2.5 记忆小技巧
    • 2.6 编译方式
    • 2.7 几个问题
      • 2.7.1 如何理解条件编译
      • 2.7.2 为什么编译器要先将代码翻译成汇编语言

1 用 gcc 直接编译

  我们平时学的 C/C++ 代码,都是文本文件,但是我们知道计算机只认识二进制,因此我们需要将C/C++代码翻译成二进制文件

  在 Windows 系统中,编辑代码和翻译过程我们都是用 VS 进行的,因为 VS 是集成的IDE环境,那么在 Linux 中我们又该如何完成代码的翻译工作呢?

  在 Linux 中,我们用到的编译器是 gcc/g++,其中gcc是对C语言进行编译,g++是对C++进行编译。因为 gcc 和 g++ 的指令操作等完全一样,本文主要是用 gcc 进行演示。
  
  我们创建一个 test.c 文件,写上代码:

#include<stdio.h>int main()
{printf("hello world\n");printf("hello Linux\n");return 0;
}

  
  如何用 gcc 对代码进行编译呢?

指令如下:

  • 「gcc」 「要编译的文件」

  
  gcc 会默认生成一个叫 a.out 的可执行文件

在这里插入图片描述

  
  那如果我想指定生成文件的名字呢?

有两种方法

  1. 「gcc 」「要编译的文件」 「-o」 「目标文件」
  2. 「gcc 」 「-o」 「目标文件」「要编译的文件」
      
    在这里插入图片描述

  但是,仅仅学会指令是远远不够的,我们学习 gcc/g++ 更重要的是学习翻译过程背后的过程,我们知道,我们写的 C语言 代码最终要形成可执行程序,要经过预处理编译汇编链接这几个过程,下面我们通过 gcc,进一步认识这四个过程。
  
  

2 翻译环境

2.1 预处理(进行宏替换)

  预处理阶段主要处理那些源文件中 # 开始的编译指令。比如:# i n c l u d e include include,# d e f i n e define define,处理的规则如下:

  • 将所有的 # d e f i n e define define 删除展开所有的宏定义
  • 处理所有的条件编译指令,如:#if#ifdef#elif#else#endif
  • 处理 # i n c l u d e include include 预编译指令,将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。
  • 删除所有注释
  • 添加行号文件名标识,方便后续编译器生成调试信息等

  
  我们创建一个code1.c文件、写一段代码

在这里插入图片描述

  这一小段代码,头文件、宏定义、注释以及条件编译都有了,正好可以看看预处理的效果。
  

我们如何看到预处理后的结果呢?我们来学一个选项 「-E 」

  • 「-E 」:进行程序翻译,在预处理做完时停下来
      

指令如下:

  • 「gcc 」「-E 」「要编译的文件」 「-o」 「目标文件」

  :预处理后的文件后缀为.i

在这里插入图片描述

  
  我们用 vim 打开 code.i 来看看

在这里插入图片描述

  

  1. 我们发现注释不见了
  2. 我们定义的宏M和N,预处理后也消失不见了,M直接别替换成100,这叫做宏替换
  3. 并且printf("hello N\n")printf("no N\n")只剩下了printf("hello N\n") 。这是因为条件编译,我们定义了N(定义了就行,可以不写值),所以预处理后保留了printf("hello N\n")
  4. 为什么我们的文件变大了呢?根本原因就是头文件展开。 在编译的时候,只要预处理完了,头文件就可以不需要了。头文件展开的意思就是把你要包含的头文件全部拷贝至你的目标文件里,形成 .i 文件。这不过这个 .i 文件我们现在将其打印出来并且写到文件里了,如果不写的话它就是内存级的,在编译器内部。同时 <stdio.h> 头文件中也包含其他的头文件,因此它会类似递归式的拷贝

  因此一个你可能只写了几百行的代码,预处理后可能有上千行。

  我们 C语言 用到的众多头文件,在系统中默认都是安装了的,一般是存在 /usr/include 路径下

在这里插入图片描述

  
  如:我们包含的头文件 <stdio.h> 一般是存在/usr/include/stdio.h 路径下

在这里插入图片描述

  
  可以用 vim 打开来看看

在这里插入图片描述

  里面的代码近 900 行,但是它有条件编译,同时 <stdio.h> 中本身也包含了其他的头文件。


  这里,我问大家一个问题,预处理后的 code1.i 还是 C语言 吗?
  答案:还是C语言
  不过他是一个已经预处理过,是一个干净的C语言了。
  

2.2 编译(生成汇编)

  编辑将C语音翻译成汇编语言
  编译过后,生成的汇编文件后缀为 .s

需要用到命令行选项 「-S 」

  • 「-S 」:从现在开始进行程序翻译,在编译步骤做完时停下来 指令如下:
  • 「gcc 」「-S 」「要编译的文件」 「-o」 「目标文件」

  我们可以从 .c 到 .s 也可以从 .i 到 .s,因为之前已经做过 .c 到 .i 了,就不再重复做预处理步骤, 直接 .i.s

在这里插入图片描述

  
  我们用 vim 打开 code1.s

在这里插入图片描述

  
  

2.3 汇编(生成机器可识别代码)

  汇编是指通过汇编器将汇编代码转变成机器可执行的指令,每一个汇编语句几乎都对应一条机器指令。就是按照汇编指令和机器指令的对照表一一的进行翻译,也不做指令优化。

先直接上指令

  • 「gcc 」「-c 」「要编译的文件」 「-o」 「目标文件」
      

如:

  • gcc -c code1.s -o code1.o
      
  • 「-c 」:从现在开始进行程序翻译,在完成汇编后停下来

  以 .o 为后缀的文件全称叫:可重定位目标文件,也就是我们所说的目标文件。目标文件在 Windows 系统下是以 .obj 结尾的

  目标文件是二进制文件,因此我们打开它是啥都看不懂的

在这里插入图片描述

  虽说 code1.o 已经是二进制文件,但是它还是无法被执行的。因为目标文件仅仅是将我们自己写的代码编成二进制了,可我们的程序中还包含着许多库方法,如printf、scanf、STL容器,此时我们的程序还没有和库方法关联起来,比如我们用了 printf 方法,可我们根本没有 printf 方法的实现,所以我们的目标文件是跑不动的。

  所以我们的程序还要经过最后一步:链接,才能形成可执行文件

  
  

2.4 链接

  链接过程没有命令行选项

指令如下:

  • gcc code1.o -o code1

  这里我们并没有指定去链接哪个库,因为我们现在的代码里没有使用任何的第三方库,我们用的都是C语言标准库的方法,gcc会帮我们去系统里找我这个程序用了 C语言 的哪个标准库。但如果我们要依赖某个第三方库,就需要指定去链接了,这点我们以后再介绍。
  生成可执行序后,程序就可以运行了

在这里插入图片描述

  

2.5 记忆小技巧

  好像预处理、编译、汇编这三步的命令行选项很难记?有什么记忆方法吗?

  他们分别是 「-E 」「-S 」「-c 」
  合起来就是键盘左上角的「esc」键,我只需要记住前两个是大写的就行了。

  而预处理、编译、汇编这三步生成的文件后缀又怎么记呢?
  他们分别是『.i』『.s』『.o』
  连起来就是iso,我们可以记ios,再将后面两个反过来
  
  

2.6 编译方式

  一般我们在编译文件时,不会像上面一样 .i.s.o全部生成一遍,上述这样做只是为了然我们了解整个翻译的过程。

  我们编译文件的习惯是将所有的文件生成 .o 文件,再将所有相关的 .o 文件一起打个包生成可执行文件

在这里插入图片描述

  
为什么喜欢这么做呢?
主要原因是:

  1. 编译器在编译时,不仅仅要形成可执行程序,还可能要形成库(所谓的库其实就是把 .o 文件了个包),如果要形成库的话就不需要编译性成可执行程序
  2. 我们目前使用的 VS 最终就形成一个可执行程序,但往往实践中可能形成 10 个、100 个可执行程序,可能你有 1000 个源文件,其中 100 个形成程序A、50 个形成程序B、60 个形成程序C……我们需要将所有的 .o 做自由组合,形成多个可执行。在编译角度,我们可先将你们全部变成 .o,最后如何形成可执行,再自己做组合
      

为什么要有链接步骤呢?

  这是因为我们要站在巨人的肩膀上
  例如我们要用到的输入输出函数,要是自己来写的话那太费劲了,每做一个项目都要自己先敲一个函数出来,而且写出来也不够好,容易出问题。因此C语言将最基本的功能给我们全部开发好,再打成包,这个包就是库
  解下来我们写代码时,我们只需要将自己的代码编译好,和C语言标准库链接形成可执行就行
  


有小伙伴可能会问:预处理时不是已经展开头文件了吗?为什么还要链接呢?

  预处理展开的仅仅只是声明,因为头文件时公开的。
  其实我们包的头文件源代码都是公开的,只有声明没有实现,实现在对应的同名 .c 文件里。.c 文件 C语言 没有给你暴露出来,直接编成库了。
  要最终形成可执行,重要的是方法,而链接就是将方法找到


  当然,上述讲的只是一般情况,你要是不喜欢也可以一次就形成可执行文件
  
  

2.7 几个问题

2.7.1 如何理解条件编译

  我们创建 code.c 文件,写下如下代码

在这里插入图片描述

  
  根据我们前面的知识,我们知道此时我们并没有定义M,执行的应是printf("社区版/免费版 version1\n")语句
  我们执行一下看看

在这里插入图片描述

  


  gcc 编译时支持我们用 「-D 」 来进行命令行级别对指定源代码进行动态添加宏

如:
定义加写值

  • gccgcc code.c -o code.exe -DM=1
      

只定义不写值

  • gccgcc code.c -o code.exe -DM

  

在这里插入图片描述

  gcc不用「-D 」选项定义宏它又会变成免费版

在这里插入图片描述

  
  gcc这合理吗?其实是合理的
  gcc编译器进行编译时第一步就是预处理,预处理的本质其实就是 让编译器编辑(修改)我们的代码! 既然预处理时,编译器能去注释,能进行宏替换,那么编译器将命令行中的 -DM 解释成 #define M ,并将其当做字符串插入到我的代码当中不过分吧。
   「-D 」相当于在命令行给代码定义宏
  


  相信对条件编译大家都能理解,大家不理解的是条件编译的用途。下面我们简单来了解一下条件编译的应用场景

  • 对一款软件通过专业读、收费标准等进行区分,使用条件编译,进行代码的动态裁剪:
    我们平时看到的某些软件,像VS、Xshell等,往往都分为专业版和社区版(收费版和免费版)。他们两者的区别主要是在功能方面,比如收费版支持100个功能,而免费版只支持50个功能。
    这些软件也都是程序员开发的,那么程序员在维护这款软件需要维护几份源代码呢?毕竟这款软件有两个版本。
    事实上,如果将同一款软件的免费版和收费版当成两个项目来看,那么公司就需要有两套班子,但其实他们功能上无非就是收费版上做一下功能的裁剪就是免费版。
    所以在公司内部我们只需要维护一份源代码即可,最终在发布的时候只需要告诉别人编译这个代码时,编译成免费的还是收费的。怎么才能做到这点呢?我们可以将软件中的功能拆分一下:公共都有的放在一个模块里,需要收费的放在一个模块里,最后用条件编译将其维护起来。
    这样一份代码通过条件编译就能对其进行裁剪,从而实现对内只需维护一份源代码,对外实现多份版本的目的。

  • Linux 内核源代码也是采用条件编译进行点裁剪
    我们的 Linux 内核,编译好了其实体积还是很大的,但有些功能在很多的小型设备上:嵌入式设备、智能家电等,上面根本就不需要Linux支持那么多功能,这时就可以用条件编译实现代码的动态裁剪

  当然,条件编译的功能远远不仅于此,但大多应用场景离我们现在的水平太远,感兴趣的小伙伴可以自行深入了解。

  
  

2.7.2 为什么编译器要先将代码翻译成汇编语言

  C语言翻译成二进制指令相信大家都能理解,因为机器只认识二进制。但为什么编译器要先将C语言翻译成汇编语言,再将汇编语言翻译成二进制呢?


为什么计算机只认识二进制

  简单来说是因为 0 和 1 是最简单的硬件电路,简单就意味着可靠,计算机通过与非门各种各样的门电路组合成各种复杂电路。
  


这里讲一下计算机的发展史
  
  计算机都是要进行输入输出的:我们将数据喂给它,它处理完后将结果返回。我们编程的本质就在在控制计算机,我们编译代码其实就是在要求计算机帮我们做这做那
  早期的计算机都是非常大的,而且其运算力非常差。早期我们没有编程,控制计算机用的是计算机上的开关,早期的计算机科学家都是在计算机前掰来掰去的,其实就是在通过开关来给计算机输入 0 和 1

  后来人们觉得开关的方式不太好,到了五六十年代,人们开始用打孔编程。

在这里插入图片描述

打孔纸带

  打了孔的地方,光能透过去,我们认为是1,否则为0。《三体》中,叶文洁向外星人发送信号时,手上捏着一条纸带,就是这个东西
  
  但打孔编程本质依然是二进制编程,二进制编程可是很恶心的。而且打孔打错了,纸就报废了,要重新打孔,浪费纸张不说还效率低下。后来人们发明了一种编程语言:汇编语言
  用汇编语言控制计算机效率无疑比直接二进制编程高很多。
  从我们的汇编语言开始,就需要一个东西:编译器。因为汇编语言本质上也是文本,所以我们需要一种编译器将汇编语言编译成对应的二进制
  


这里有个问题:第一个汇编语言编译器是用什么写的呢?
  这个编译器要编译汇编语言,那编译器自己应该用什么语言来写呢?
  用汇编吗?你用还没法翻译成二进制的汇编,来将汇编翻译成二进制,这不鸡蛋和鸡吗?

  因此第一版编译汇编的编译器,是用二进制写的。先用二进制写一个二进制版的汇编编译器。有了第一个编译器,此时就可以编译汇编语言了,此时我们就可以用汇编语言写一份汇编版本的编译器,第一版的编译器就可以不要了,此后我们就可以用自己语言写的编译器编译自己语言。这个过程叫做编译器的自举过程
  不仅如此,语言也是可以自举的。比如C++推出C++11,但此时的编译器只支持C++98,这时就可用98写个能编11的编译器,再用C++11进行重写

  最早期的,比较好的操作系统叫 Unix,它第一版本就是由肯·汤普逊用汇编语言写出来的,后来丹尼斯里奇发明了 C语言,肯·汤普逊和丹尼斯里奇即一起用C语言把 Unix 进行重构,发布的 C语言 版本的 Unix。我什么肯·汤普逊最开始用汇编语言写,因为最开始只有汇编,后来 C语言 出来了,C语言 对应的编译器也诞生了,为了代码本身的可维护性,他就把 Unix 操作系统调整为 C语言 了。
  


  再后来,人们觉得汇编语言也太麻烦,所以基于汇编语言产生了许多分支,编译型语言在那个阶段就开始爆发了。最典型的就是 70 年代产生的 C语言,再到后来的 C++/java/go
  

在这里插入图片描述

  
  现在有了 C语言,C语言 最终肯定也要翻译成二进制。现在的问题是,我们是直接将C语言翻译成二进制还是先翻译成汇编语言再翻译成二进制。
  我们肯定会选择方案二。为什么呢?

  首先将C语言翻译成汇编语言,毕竟还是从文本到文本,它的翻译难度相对较低;其次,在C语言产生之前,汇编语言已经发展了很多年了,我们只需要将C翻译成汇编,而将汇编翻译成二进制这项工作已经发展的很成熟,可以不用做了,我们可以站在巨人的肩膀上
  如果直接将 C 翻译成二进制,那么翻译的成本会特别高,而且 C++ 等后来者是基于C语言发明出来的,你让我 C++ 怎么办,难道我 C++ 也要直接翻译成二进制吗?
  我们要学会站在巨人的肩膀上,计算机每一阶段的发展都经过了十几年,我们要将每一阶段的发展好好用上。

  而编译是逆历史的过程:C语言 -> 汇编 -> 二进制
  

在这里插入图片描述

  
  
  
  


  好啦,本期关于编译器 gcc/g++ 就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在 Linux 的学习路上一起进步!

相关文章:

【Linux系统】—— 编译器 gcc/g++ 的使用

【Linux系统】—— 编译器 gcc/g 的使用 1 用 gcc 直接编译2 翻译环境2.1 预处理&#xff08;进行宏替换&#xff09;2.2 编译&#xff08;生成汇编&#xff09;2.3 汇编&#xff08;生成机器可识别代码&#xff09;2.4 链接2.5 记忆小技巧2.6 编译方式2.7 几个问题2.7.1 如何理…...

[微服务]注册中心优化

环境隔离 企业实际开发中&#xff0c;往往会搭建多个运行环境&#xff0c;例如&#xff1a; 开发环境测试环境预发布环境生产环境 这些不同环境之间的服务和数据之间需要隔离。 还有的企业中&#xff0c;会开发多个项目&#xff0c;共享nacos集群。此时&#xff0c;这些项目…...

C++ ——— 模拟实现 vector 类

目录 vector 类的框架 无参数的构造函数 析构函数 获取有效数据个数 获取容量 重载 [] 运算符 可读可写版本 只可读版本 扩容 尾插 实现迭代器 可读可写版本 只可读版本 自定义设置size长度和内容 在任意位置插入 删除任意位置的数据 赋值重载 vector 类的框…...

大华相机DH-IPC-HFW3237M支持的ONVIF协议

使用libONVIF C库。 先发现相机。 配置 lib目录 包含 编译提示缺的文件&#xff0c;到libonvif里面拷贝过来。 改UDP端口 代码 使用msvc 2022的向导生成空项目&#xff0c;从项目的main示例拷贝过来。 CameraOnvif.h #pragma once#include <QObject> #include &l…...

【Java】常用工具类方法:树形结构、获取IP、对象拷贝、File相关、雪花算法等

1、生成子孙树 /*** 生成子孙树** param dataArray 遍历所有数据, 每个数据加到其父节点下* return 子孙树json*/public static JSONArray makeTree(JSONArray dataArray) {List<Map<String, Object>> data new ArrayList<>();for (int i 0; i < dataAr…...

豆瓣电影Top250的数据采集与可视化分析(scrapy+mysql+matplotlib)

文章目录 豆瓣电影Top250的数据采集与可视化分析(scrapy+mysql+matplotlib)写在前面数据采集(Visual Studio Code+Navicat)1.观察网页信息2.编写Scrapy代码(Visual Studio Code)2.1 创建Scrapy项目`doubanProject`2.2 创建爬虫脚本`douban.py`2.3 修改`douban.py`的代码2…...

2024微短剧行业生态洞察报告汇总PDF洞察(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p39072 本报告合集洞察从多个维度全面解读微短剧行业。在行业发展层面&#xff0c;市场规模与用户规模双增长&#xff0c;创造大量高收入就业岗位并带动产业链升级。内容创作上&#xff0c;精品化、品牌化趋势凸显&#xff0c;题材走…...

PHP语言的数据库交互

PHP语言的数据库交互 引言 在现代Web开发中&#xff0c;数据库是存储和管理应用数据的重要组成部分。随着互联网的快速发展&#xff0c;网站和应用程序对数据存储和操作的需求变得越来越复杂。PHP作为一种广泛使用的服务器端脚本语言&#xff0c;提供了多种数据库交互的方法&…...

flutter跨端UI框架简介

flutter跨端UI框架简介 简介 Flutter是由Google开发的开源应用开发框架&#xff0c;主要用于构建高性能、跨平台的移动、Web和桌面应用程序。Flutter使用Dart语言&#xff0c;提供了一套丰富的Widgets&#xff0c;使开发者能够快速创建美观的用户界面。其最大特点是热重载功能…...

自动化标注平台开源,基于 yolov8标注平台可本地部署

yolov8标注平台本地部署&#xff08;docker部署&#xff09;&#xff0c;已调通yolov8模型自动预标注功能。 下面开始背景知识…… 1&#xff09;数据标注为什么在人工智能时代如此重要&#xff1f; 数据标注在人工智能时代如此重要&#xff0c;原因如下&#xff1a; 为机器…...

Walrus Learn to Earn计划正式启动!探索去中心化存储的无限可能

本期 Learn to Earn 活动将带领开发者和区块链爱好者深入探索 Walrus 的技术核心与实际应用&#xff0c;解锁分布式存储的无限可能。参与者不仅能提升技能&#xff0c;还能通过完成任务赢取丰厚奖励&#xff01;&#x1f30a; 什么是 Walrus&#xff1f; 数据主权如今正成为越…...

第35天:安全开发-JavaEE应用原生反序列化重写方法链条分析触发类类加载

时间轴&#xff1a; 序列化与反序列化图解&#xff1a; 演示案例&#xff1a; Java-原生使用-序列化&反序列化 Java-安全问题-重写方法&触发方法 Java-安全问题-可控其他类重写方法 Java-原生使用-序列化&反序列化 1.为什么进行序列化和反序列化&#xff1…...

【mptcp】ubuntu18.04和MT7981搭建mptcp测试环境操作说明

目录 安装ubuntu18.04,可以使用虚拟机安装... 2 点击安装VMware Tool 2 更新ubuntu18.04源... 4 安装ifconfig指令工具包... 5 安装vim工具包... 5...

【数据分析(二)】初探 Pandas

目录 引言1. 基本数据结构1.1. Series 的初始化和简单操作1.2. DataFrame 的初始化和简单操作1.2.1. 初始化与持久化1.2.2. 读取查看1.2.3. 行操作1.2.4. 列操作1.2.5. 选中筛查 2. 数据预处理2.0. 生成样例表2.1. 缺失值处理2.2. 类型转换和排序2.3. 统计分析 3. 数据透视3.0.…...

第9章:Python TDD解决货币对象相等性比较难题

写在前面 这本书是我们老板推荐过的&#xff0c;我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后&#xff0c;我突然思考&#xff0c;对于测试开发工程师来说&#xff0c;什么才更有价值呢&#xff1f;如何让 AI 工具更好地辅助自己写代码&#xff0c;或许…...

更新布局元素的属性

每个布局元素都有一组可以通过编程来更新的属性.布局元素有很多种不同的类型,如图例,图形,文本,地图整饰等等. 操作方法: 1.打开目标活动地图文档 2.打开python窗口 3.导入arcpy模块 import arcpy.mapping as mapping 4.引用当前活动地图文档,把该引用赋值给变量 mxd map…...

UDP協議與代理IP介紹

UDP&#xff0c;全稱是用戶數據報協議&#xff08;User Datagram Protocol&#xff09;&#xff0c;是Internet協議套組的一部分&#xff0c;與TCP協議一道工作。與TCP相比&#xff0c;UDP可以理解為一個更“羽量級”的協議。它不需要像TCP那樣在數據傳輸開始之前建立連接&…...

QT 中 UDP 的使用

目录 一、UDP 简介 二、QT 中 UDP 编程的基本步骤 &#xff08;一&#xff09;包含头文件 &#xff08;二&#xff09;创建 UDP 套接字对象 &#xff08;三&#xff09;绑定端口 &#xff08;四&#xff09;发送数据 &#xff08;五&#xff09;接收数据 三、完整示例代…...

leetcode刷题记录(七十二)——146. LRU 缓存

&#xff08;一&#xff09;问题描述 146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09;146. LRU 缓存 - 请你设计并实现一个满足 LRU (最近最少使用) 缓存 [https://baike.baidu.com/item/LRU] 约束的数据结构。实现 LRUCache 类&#xff1a; * LRUCache(int capacity)…...

深圳大学-计算机系统(3)-实验一MIPS指令集实验

实验目标 a) 了解WinMIPS64的基本功能和作用&#xff1b; b) 熟悉MIPS指令、初步建立指令流水执行的感性认识&#xff1b; c) 掌握该工具的基本命令和操作&#xff0c;为流水线实验作准备。 实验内容 按照下面的实验步骤及说明&#xff0c;完成相关操作记录实验过程的截图&a…...

Redis:介绍和认识,通用命令,数据类型和内部编码,单线程模型

介绍和认识 Redis是一个基于内存的&#xff0c;高性能的&#xff0c;支持许多数据类型的NoSQL数据库&#xff0c;可以持久化&#xff0c;也支持分布式。 在许多的互联网产品中&#xff0c;对于数据库的访问速度要求很高&#xff0c;例如Mysql数据库无法满足其要求&#xff0c…...

嵌入式开发之STM32学习笔记day20

STM32F103C8T6 PWR电源控制 1 PWR简介 PWR&#xff08;Power Control&#xff09;电源控制单元是STM32微控制器中一个重要的组成部分&#xff0c;它负责管理系统的电源管理功能&#xff0c;以优化功耗并提高效率。PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编…...

[Java 基础]数组

什么是数组&#xff1f;想象一下&#xff0c;你需要存储 5 个学生的考试成绩。你可以声明 5 个不同的 int 变量&#xff0c;但这会显得很笨拙。数组提供了一种更简洁、更有组织的方式来存储和管理这些数据。 数组可以看作是相同类型元素的集合&#xff0c;这些元素在内存中是连…...

霍尔效应传感器的革新突破:铟化铟晶体与结构演进驱动汽车点火系统升级

一、半导体材料革新&#xff1a;铟化铟晶体的电压放大机制 铟化铟&#xff08;InSb&#xff09;晶体因其独特的能带结构&#xff0c;成为提升霍尔电压的关键材料。相较于传统硅基材料&#xff0c;其载流子迁移率高出3-5倍&#xff0c;在相同磁场强度下可显著放大霍尔电压。其作…...

Ansible 剧本精粹 - 编写你的第一个 Playbook

Ansible 剧本精粹 - 编写你的第一个 Playbook 如果说 Ansible Ad-Hoc 命令像是你对厨房里的助手发出的零散口头指令(“切个洋葱”、“烧开水”),那么 Playbook 就是一份完整、详细、写在纸上的菜谱。它列明了所有需要的“食材”(变量),详细的“烹饪步骤”(任务),甚至还…...

CSS选择子元素

通过选择器 为所有子元素应用样式。以下是几种常见方法&#xff1a; 1. 选择所有直接子元素&#xff08;不包括孙级&#xff09; css 复制 下载 .parent > * {/* 样式规则 */color: red; } > 选择器&#xff1a;只匹配直接子元素 * 通配符&#xff1a;匹配任意类型…...

AX513CE 是一款针对模组渠道市场前端IPC应用而设计的数字SOC芯片 支持高清CMOS Sensor输入 国产品牌

AX513CE 是一款针对模组渠道市场前端IPC应用而设计的数字SOC芯片 支持高清CMOS Sensor输入 国产品牌 产品概述&#xff1a; AX513CE 是一款针对模组渠道市场前端IPC应用而设计的数字SOC芯片&#xff0c;支持高清CMOS Sensor输入&#xff0c;经ISP处理、视频前处理以及音视频编…...

MyBatis 的动态 SQL

1. 动态 SQL 的定义 动态 SQL 是 MyBatis 的核心特性之一&#xff0c;它允许开发者根据运行时条件动态生成 SQL 语句。通过特殊的 XML 标签或注解语法&#xff0c;实现 SQL 的灵活拼接&#xff0c;避免在 Java 代码中手动拼接 SQL 字符串的复杂性和安全风险。 2. 核心作用 条…...

python版若依框架开发:python版若依部署

python版若依框架开发 从0起步,扬帆起航。 python版若依部署文章目录 python版若依框架开发1.源码2.概述3.部署1.源码 https://gitee.com/insistence2022/RuoYi-Vue-FastAPI 请诸君移步上述链接,即可对python版若依项目进行初步了解。 2.概述 若依框架本身基于java,可以快…...

AWS 成本异常检测IAM策略

问题 审计人员需要看AWS 成本异常检测&#xff0c;则需要开通这个权限。 IAM 自定义策略 {"Version": "2012-10-17","Statement": [{"Action": ["ce:Get*"],"Effect": "Allow","Resource"…...