嵌入式Linux之C语言开发基础
一、C 语言编译过程
Linux 的 C 语言开发,一般选择 GCC 工具链进行编译,示例:
1.mkdir helloworld
2.cd helloworld
// 1.main.c
#include "hello.h"
int main()
{say_hello();return 0;
} // 2.hello.h
#ifndef __HELLO_H__
#define __HELLO_H__void say_hello();#endif// 3.hello.c
#include "hello.h"
#include <stdio.h>
void say_hello()
{printf("Hello world!\n");
}
采用如下命令编译可执行文件并执行:
命令行:
gcc main.c hello.c -o main
./main输出:helloworld!-o: output 的缩写,表示输出,用于指定输出文件名。
1.1 预处理命令
在 C 语言编译过程中,预处理是其中的第一个阶段,它的主要目的是处理源代码文件中的预处理指令,将它们转换成编译器可以识别的形式。预处理主要包含宏替换、文件包含、条件编译、注释移除等几种任务。预处理的输出通常是经过预处理后的源代码文件,它会被保存成一个临时文件,并作为编译器的输入。预处理器处理后的文件通常会比原始源文件大,因为它会展开宏和包含其他文件的内容。
gcc -E hello.c -o hello.i
gcc -E main.c -o main.i
➢ -E: Expand(展开)的缩写,该参数指定 gcc 执行预处理操作。
➢ .i: intermediate(中间的)的缩写,预处理后的源文件通常以.i 作为后缀。
main.i 解读:
# 0 "main.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 0 "<command-line>" 2
# 1 "main.c"
# 1 "hello.h" 1void say_hello();
# 2 "main.c" 2
int main()
{say_hello();return 0;
}
预处理后的.i 文件包含了经过 C 预处理器处理的源代码及行控制指令等内容。行控制:
# 行号 "文件名" 标志行号和文件名表示从下一行开始的源代码来源于哪个文件的哪一行。标志可以是数字 1,2,3,4,每个数字的含义如下:➢ 1: 表示接下来的内容开始于一个新的文件。➢ 2: 表示控制权从被包含的文件返回。这用于当预处理器完成一个包含文件的读取,回到包含它的文件继续处理时。➢ 3: 指示接下来的内容来自系统头文件。➢ 4: 表明接下来的内容应被视为被 extern "C"包围,这主要用于 C++中,以指示 C 链接约定。 extern C 是 C++中的关键字组合,我们不必关注。
注: 行号为 0 通常是预处理器的一种特殊标记用法,并不指向源代码中的实际行号。它可能用于初始化或特殊标记,比如标识文件的开始,而不直接对应于源代码中的行。我们只需要知道.i 文件是将源码中宏定义处理之后的源文件,其它内容了解即可。
1.2 编译
编译阶段,编译器会将经过预处理的源代码文件转换成汇编代码。在这个阶段,编译器会将源代码翻译成机器能够理解的中间代码,包括词法分析、语法分析、语义分析和优化等过程。编译器会检查代码的语法和语义,生成对应的汇编代码。编译阶段是整个编译过程中最复杂和耗时的阶段之一,它对源代码进行了深入的分析和转换,确保了程序的正确性和性能。
gcc -S main.i -o main.s
gcc -S hello.i -o hello.s
➢ -S: Source(源代码)的缩写,该参数指定 gcc 将预处理后的源码编译为汇编语言。
➢ .s: Assembly Source(汇编源码)的缩写,通常编译后的汇编文件以.s 作为后缀。
1.3 汇编
汇编阶段是 C 语言编译过程中的重要阶段,它将编译器生成的中间代码或汇编代码转换成目标机器的机器语言代码,也就是目标代码。这个阶段由汇编器( Assembler)完成,其主要任务是将汇编指令翻译成目标机器的二进制形式。主要包含以下几个任务:符号解析、指令翻译、地址关联、重定位、代码优化。最终,汇编器会将翻译和处理后的目标代码输出到目标文件中,用于后续的链接和生成可执行程序或共享库文件。
gcc -c main.s -o main.o
gcc -c hello.s -o hello.o
➢ -c: 可以被理解为 Compile or Assemble(编译或汇编),该参数可以指定 gcc 将汇编代码翻译为机器码,但不做链接。此外,该参数也可以用于将.c 文件直接处理为机器码,同样不做链接。
➢ -o: Object 的缩写,通常汇编得到的机器码文件以.o 为后缀。
反汇编:
objdump -d main.o
1.4 链接
链接阶段,由链接器完成。链接器将各个目标文件以及可能用到的库文件进行链接,生成最终的可执行程序。在这个阶段,链接器会解析目标文件中的符号引用,并将它们与符号定义进行匹配,以解决符号的地址关联问题。链接器还会处理全局变量的定义和声明,解决重定位问题,最终生成可执行文件或共享库文件。
1.4.1 链接方式
我们在 say_hello()函数中调用了 printf()函数,这个函数是在 stdio.h 中声明的,后者来源于 glibc 库, printf()的实现在 glibc 的二进制组件中,通常是在共享库(如libc.so)或静态库(如 libc.a)文件中。因此,我们除了要链接 main.o、 hello.o,还需要和 glibc 库的文件链接。通常, C 语言的链接共有三种方式:静态链接、动态链接和混合链接。三者的区别就在于链接器在链接过程中对程序中库函数调用的解析。
1. 静态链接
将所有目标文件和所需的库在编译时一并打包进最终的可执行文件。库的代码被复制到最终的可执行文件中,使得可执行文件变得自包含,不需要在运行时查找或加载外部库。
gcc -static main.o hello.o -o main
-static: 该参数指示编译器进行静态链接,而不是默认的动态链接。使用这个参数, GCC 会尝试将所有用到的库函数直接链接到最终生成的可执行文件中,包括 C 标准库(libc)、数学库(libm)和其他任何通过代码引用的外部库。
2. 动态链接
库在运行时被加载,可执行文件包含了需要加载的库的路径和符号信息。动态链接的可执行文件比静态链接的小,因为它们共享系统级的库代码。与静态链接不同,库代码不包含在可执行文件中。
① 方式一:没有添加-static 关键字, gcc 默认执行动态链接,即 glibc 库文件没有包含到可执行文件中。
gcc main.o hello.o -o main
② 方式二:我们也可以将自己编写的部分代码处理为动态库。执行下面的指令将 hello.o 编译为动态链接库 libhello.so。
gcc -fPIC -shared -o libhello.so hello.o
➢ -fPIC: 这个选项告诉编译器为“位置无关代码(Position Independent Code)”生成输出。在创建共享库时使用这个选项是非常重要的,因为它允许共享库被加载到内存中的任何位置,而不影响其执行。这是因为位置无关代码使用相对地址而非绝对地址进行数据访问和函数调用,使得库在被不同程序加载时能够灵活地映射到不同的地址空间。
➢ -shared: 这个选项指示 GCC 生成一个共享库而不是一个可执行文件。共享库可以被多个程序同时使用,节省了内存和磁盘空间。
➢ -o libhello.so: 这部分指定了输出文件的名称。 -o 选项后面跟着的是输出文件的名字,这里命名为 libhello.so。按照惯例, Linux 下的共享库名称以 lib 开头,扩展名为.so(表示共享对象)。
➢ hello.o: 这是命令的输入文件,即之前编译生成的目标文件。在这个例子中, GCC 会将 hello.o 中的代码和数据打包进最终的共享库 libhello.so 中。
上述命令的作用是:使用 GCC,采用位置无关代码的方式,从 hello.o 目标文件创建一个名为 libhello.so 的动态共享库文件。
编译完成后查看刚刚编译的动态链接库(命令行输入):
ll
3. 混合链接
某些库静态链接,而其他库动态链接。这种方式结合了静态链接和动态链接的优点。执行下面的指令可以将 hello.o 编译为静态链接库 libhello.a
ar crv libhello.a hello.o
➢ ar: 归档命令,用于处理静态库文件。
➢ crv: ar 命令的选项,由三个字符组成,每个字符代表一个选项:
➢ c: 创建归档文件。如果指定的归档文件不存在, ar 会创建它。
➢ r: 替换归档文件中现有的文件或者向归档文件中添加新文件。如果 hello.o已经在 libhello.a 中,它会被新版本替换;如果不存在,则会被添加。
➢ v: 详细模式(verbose mode),在处理文件时显示详细信息。使用这个选项, ar 会列出它正在执行的操作,包括哪些文件被添加或替换。
➢ libhello.a: 要创建或更新的静态库文件的名称。按照惯例, Linux 下的静态库文件名以 lib 开头,并以.a 作为文件扩展名。
➢ hello.o: 输入文件,即要添加到静态库 libhello.a 中的目标文件。此处只有一个目标文件 hello.o,但 ar 命令支持同时指定多个文件。
静态链接 libhello.a 生成的 main 比 main_d 文件要大一些,这是因为hello 库的代码被复制到了可执行文件 main 中,和动态链接相比,执行速度略高,但是二进制代码的复用性差,略微增加了二进制文件的体积。
需要注意的是,虽然我们静态链接了 libhello.a 库,但是 main 文件在执行时依然需要动态链接 glibc 的库。因此,这种方式实质上并非静态链接,而是混合链接。
1.4.2 gblic 的动态库和静态库
glibc 的动态库和静态库分别位于/usr/lib/x86-64_64-linux-gnu/目录下的libc.so 和 libc.a 文件中。
二、Makefile 基础
Makefile 是一种用于管理和自动化软件编译过程的文本文件。它通常包含了一系列规则,这些规则描述了如何根据源代码文件生成可执行文件或者其他目标文件。 Makefile的核心概念是规则和依赖关系,规则定义了如何生成一个或多个目标文件,而依赖关系则指定了生成目标文件所需要的源文件或其他依赖文件。下面我们通过一步一步编写Makefile 来学习 Makefile 规则。
2.1 安装 build-essential 工具包
sudo apt install -y build-essential
2.1 编写 Makefile
vim Makefile
# Makefile 内容通常由以下部分组成
# <目标>: <前置依赖>
# <需要执行的命令>
# 放在第一个的是默认目标
# 目标为编译出 main 文件,依赖 main.o 和 hello.o 文件
# 编译的命令为 gcc -o main hello.o main.omain: hello.o main.ogcc -o main hello.o main.o# main.o 目标依赖 main.c hello.h
# 编译命令为 gcc -c main.c
main.o: main.c hello.hgcc -c main.c# hello.hello.c hello.h
# 编译命令为 gcc -c hello.c
hello.o: hello.c hello.hgcc -c hello.c# clean 目标可以清理编译的临时文件
clean:rm main main.o hello.
2.3 文件内容解读
规则是 Makefile 的构建单元, Make 工具通过解析这些规则来执行构建过程。
① 规则的基本结构:我们用空行将 Makefile 的不同规则划分开来。规则有两行构成,第一行为目标和前置依赖,二者通过冒号区分开来,目标在前,前置依赖在后。
# <目标>: <前置依赖> # <需要执行的命令>
② 目标:本条规则需要生成的目标文件名。
③ 前置依赖:生成目标文件需要的依赖文件列表。
④ 命令:一系列将被 Shell 执行的命令,用于从前置依赖构建目标。
需要注意的是, Makefile 中每个规则的命令必须以一个制表符(tab)开始,而不能是空格。否则会提示“缺失分隔符”。
⑤ 上文提到, gcc 的-c 参数不仅可以将汇编代码转换为机器码,还可以直接将 C 语言源文件转换为机器码, gcc -c main.c 就是第二种用法,这里省略了-o main.o。默认情况下,在指定-c 参数时, gcc 会将与源文件名去掉扩展名再加上后缀.o 作为目标文件的名称。
2.4 测试
① 执行 make 命令:
make
出现提示:make: "main"已是最新。提示我们“main”已是最新,这是因为上面的操作已经生成了最终的可执行文件“main”,要看到 make 的作用,需要先将之前编译好的文件删除
rm main.o hello.o main
② 重新执行 make
③ 同理,执行 make clean 可以执行 clean 目标:
make clean
这个目标我们定义了如何清理编译的残留文件和结果。执行这个目标后,我们的编译结果和临时文件就都被清理了。
这就是 Makefile,可以批处理进行一键编译,大大提高了编译效率。
2.5 引入变量
# 定义变量 objects
objects := hello.o\main.o# 在目标中引入变量
main: $(objects)gcc -o main $(objects)main.o: main.c hello.hgcc -c main.chello.o: hello.c hello.hgcc -c hello.c# clean 目标中也可以引入变量
clean:rm main $(objects)
➢ objects 为变量名
➢ :=的组合相当于 C 语言中的=,表示赋值
➢ :=后面为变量的值
➢ \为续行符,表示命令或定义延续到下一行。此处的作用是将 hello.o 和 main.o 合并为一行,此处的定义等价于 objects := hello.o main.o。
➢ $(变量名)表示获取变量的值
2.6 引入 make 自动推导
make 可以根据目标自动加入所需的依赖文件和命令。例如 main.o 目标,会默认将main.c 作为依赖加入,同时也可以自动推导出编译 main.o 的命令,于是我们的Makefile 就可以改成以下内容:
objects := hello.o\main.omain: $(objects)gcc -o main $(objects)# 利用 make 的自动推导
clean:rm main $(objects)
要注意的是,虽然这种方式精简 Makefile 的内容,但是当没有显式声明的依赖文件发生更改时 Make 无法追踪。
# Makefile 内容通常由以下 3 部分组成
# <目标名称>:<前置依赖>
# \t<需要执行的命令>
# 定义变量 objects
objects := hello.o \main.o
# 放在第一个的是默认目标
# 目标是编译出 main 文件 依赖 hello.o 和 main.o 文件
# 编译的命令是 gcc hello.o main.o -o main
main: $(objects)gcc $(objects) -o main#目标是 main.o 依赖 main.c 和 hello.h
#编译的命令是 gcc -c main.c
# main.o: main.c hello.h
# gcc -c main.c
main.o: hello.h
#目标是 hello.o 依赖 hello.c 和 hello.h
#编译的命令是 gcc -c hello.c
# hello.o: hello.c hello.h
# gcc -c hello.c
hello.o: hello.h
clean:rm main $(objects)
总结:只有在 Makefile 中显式声明依赖的头文件才会被追踪,当它们发生更改时,重新执行 make 命令,会再次执行相应规则的命令。
2.7 引入伪目标
伪目标并不代表实际的文件名,它们更多的是行为或动作的标识符。伪目标并不生成具体文件。
① .PHONY 是 Makefile 中一个特殊的目标,用于声明其它目标是伪目标。
② 语法: .PHONY:<伪目标名称>
③ 注意到,目标为 clean 的规则没有前置依赖,这是因为它是用来执行清理操作的,并不是要生成名为 clean 的文件,因此不需要前置依赖。我们可以将clean 声明为伪目标。
# 声明伪目标
.PHONY: clean# clean 目标中也可以引入变量
clean:rm main $(objects)
为什么需要声明伪目标?KEY:将某些不生成目标文件的行为或动作(如清理、安装)声明为伪目标可以确保无条件执行规则下的命令。即便执行 make 命令时当前目录下存在与目标同名的文件,依然可以得到我们期望的效果。
2.8 忽略错误
# 声明伪目标
.PHONY: clean# clean 目标中也可以引入变量
clean:-rm main $(objects)
rm 前面的-告诉 make,如果该命令执行失败,不要停止执行剩余的过程,即忽略错误。效果如下:
2.9 目标名和命令中输出文件名的关系
make 输出的文件名取决于规则下的命令,而目标名称决定 make 追踪的目标文件名。如果二者不一致, make 就会认为目标文件不存在而不断执行命令。我们应确保命令生成的目标文件名和目标名一致。
三、安装 vscode-makefile-term 插件
在插件市场搜索并安装 vscode-makefile-term 插件,完成后,在 VScode 中打开Makefile 文件,可以看到每个 target 上方都出现了执行按钮。
点击这些按钮 vscode-makefile-term 插件就会帮助我们执行相应的 target。
就不用老是在命令行窗口输指令啦!
相关文章:
嵌入式Linux之C语言开发基础
一、C 语言编译过程 Linux 的 C 语言开发,一般选择 GCC 工具链进行编译,示例: 1.mkdir helloworld 2.cd helloworld // 1.main.c #include "hello.h" int main() {say_hello();return 0; } // 2.hello.h #ifndef __HELLO_H__ #de…...
std::accumulate
std::accumulate 是 C 标准库中的一个算法,定义在 <numeric> 头文件中。它用于计算给定范围内元素的累积值(通常是一个和,但也可以是其他类型的累积操作)。 template< class InputIt, class T > T accumulate( Input…...
计算机网络 (33)传输控制协议TCP概述
一、定义与基本概念 TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。它工作在OSI模型的第四层,即传输层,为用户提供可靠的、有序的和无差错的数据传输服务。TCP协议与UDP协议是传输层的两大主要协议,但两者在设计上有明显的不同&…...
Gitee图形界面上传(详细步骤)
目录 1.软件安装 2.安装顺序 3.创建仓库 4.克隆远程仓库到本地电脑 提交代码的三板斧 1.软件安装 Git - Downloads (git-scm.com) Download – TortoiseGit – Windows Shell Interface to Git 2.安装顺序 1. 首先安装git-2.33.1-64-bit.exe,顺序不能搞错2. …...
【STM32-学习笔记-6-】DMA
文章目录 DMAⅠ、DMA框图Ⅱ、DMA基本结构Ⅲ、不同外设的DMA请求Ⅳ、DMA函数Ⅴ、DMA_InitTypeDef结构体参数①、DMA_PeripheralBaseAddr②、DMA_PeripheralDataSize③、DMA_PeripheralInc④、DMA_MemoryBaseAddr⑤、DMA_MemoryDataSize⑥、DMA_MemoryInc⑦、DMA_DIR⑧、DMA_Buff…...
苍穹外卖08——(涉及接收日期格式数据、ApachePOI导出报表、sql获取top10菜品数据)
营业额统计 service层 在需要处理空值、与数据库交互或使用集合时,Integer 、Double是更好的选择。 // 导入string工具类 import org.apache.commons.lang.StringUtils; Service // 标记该类为Spring的服务组件 Slf4j // 引入日志功能 public class Repor…...
Node.js——fs(文件系统)模块
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
【Docker】入门教程
目录 一、Docker的安装 二、Docker的命令 Docker命令实验 1.下载镜像 2.启动容器 3.修改页面 4.保存镜像 5.分享社区 三、Docker存储 1.目录挂载 2.卷映射 四、Docker网络 1.容器间相互访问 2.Redis主从同步集群 3.启动MySQL 五、Docker Compose 1.命令式安装 …...
Ubuntu中使用miniconda安装R和R包devtools
安装devtools环境包 sudo apt-get install gfortran -y sudo apt-get install build-essential -y sudo apt-get install libxt-dev -y sudo apt-get install libcurl4-openssl-dev -y sudo apt-get install libxml2.6-dev -y sudo apt-get install libssl-dev -y sudo apt-g…...
大语言模型预训练、微调、RLHF
转发,如有侵权,请联系删除: 1.【LLM】3:从零开始训练大语言模型(预训练、微调、RLHF) 2.老婆饼里没有老婆,RLHF里也没有真正的RL 3.【大模型微调】一文掌握7种大模型微调的方法 4.基于 Qwen2.…...
啥!GitHub Copilot也免费使用了
文章目录 前言免费版直接修复代码多文件上下文Agent模式总结 前言 最近,GitHub 给开发者们带来了一个好消息:他们的 AI 编程助手 GitHub Copilot 现在可以免费使用了!以前,每个月要花 10 美元才能享受的服务,现在对所…...
【Ubuntu与Linux操作系统:五、文件与目录管理】
第5章 磁盘存储管理 5.1 Linux磁盘存储概述 磁盘存储是Linux系统存储数据的重要组件,它通过分区和文件系统组织和管理数据。Linux支持多种文件系统,如ext4、xfs和btrfs,并以块的形式管理存储设备。 1. 分区与文件系统: 分区&am…...
【PDF转Word】 PDF在线转word文档 好用!优质网站资源推荐
大家在工作与学习中,经常需要将PDF文件转换为Word格式以便进行编辑和修改。很多人都不知道怎么操作,今天我们介绍一个非常好用的工具:小白工具网,可以在线帮忙大家快速把PDF转换成word格式。 小白工具网提供的PDF转Word功能&…...
计算机网络 (38)TCP的拥塞控制
前言 TCP拥塞控制是传输控制协议(Transmission Control Protocol,TCP)避免网络拥塞的算法,是互联网上主要的一个拥塞控制措施。 一、目的 TCP拥塞控制的主要目的是防止过多的数据注入到网络中,使网络能够承受现有的网络…...
构造函数的原型原型链
代码示例 // 定义一个构造函数 Test function Test() {this.name 张三 }; //向构造函数的原型添加一个属性 age18 Test.prototype.age 18;//使用构造函数 Test 来实例化一个新对象 const test new Test();//向 Object.prototype 添加了一个名为 sex 的属性,其值…...
2025华数杯国际赛A题完整论文讲解(含每一问python代码+数据+可视化图)
大家好呀,从发布赛题一直到现在,总算完成了2025“华数杯”国际大学生数学建模竞赛A题Can He Swim Faster的完整的成品论文。 本论文可以保证原创,保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文…...
[RabbitMQ] RabbitMQ运维问题
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
GenAIOps:生成式 AI 运维 - 实用指南
https://medium.com/google-cloud/genaiops-operationalize-generative-ai-a-practical-guide-d5bedaa59d78 作者:Dr Sokratis Kartakis 从创意到生产:使用生成式 AI 和运维 (GenAIOps) 概述 生成式 AI (GenAI) 的世界充满了令人兴奋的可…...
用户界面软件04
后果 使用这种架构很容易对两个层面的非功能性需求进行优化,但是你仍然需要小心不要将功能 需求重复实现。 现在,两个层面可能有完全不同的设计。比如,用户界面层可能使用配件模型(Widget Model), 以大量的…...
分布式系统设计:Java的秘密基地布局
分布式系统设计是Java企业级开发中的一个关键领域,它涉及到构建高可用、可扩展、高性能的系统。以下是分布式系统设计的一些核心概念和实践: 3.1 分布式系统的特点 分布式系统由多个独立的计算机节点组成,这些节点通过网络连接在一起&#x…...
【Redis学习 | 第5篇】Redis缓存 —— 缓存的概念 + 缓存穿透 + 缓存雪崩 + 缓存击穿
文章目录 完成任务1. 什么是缓存2. 添加商户缓存3. 缓存更新策略3.1 主动更新 4. 缓存穿透5. 缓存雪崩6. 缓存击穿6.1 使用互斥锁查询商铺信息6.2 使用逻辑过期查询商铺信息 7. 封装 Redis 工具类 完成任务 1. 什么是缓存 缓存:数据交换的缓冲区(Cache…...
MySQL索引覆盖(覆盖索引, Covering Index)
文章目录 说明MySQL索引覆盖(覆盖索引, Covering Index)覆盖索引的概念覆盖索引的示例示例查询及索引覆盖情况覆盖索引的性能优势覆盖索引的实现条件覆盖索引 vs 非覆盖索引覆盖索引的限制如何设计覆盖索引覆盖索引的实际案例场景 1:电商系统…...
VUE3 provide 和 inject,跨越多层级组件传递数据
provide 和 inject 是 Vue 3 提供的 API,主要用于实现祖先组件与后代组件之间的依赖注入。它们可以让你在组件树中,跨越多层组件传递数据,而不需要通过 props 或事件的方式逐层传递。这个机制主要用于状态共享、插件系统或某些跨层级的功能。…...
【UE5 C++课程系列笔记】29——在UE中使用第三方库的流程
目录 前言 步骤 一、新建插件 二、创建第三方库 三、使用第三方库 前言 主要就是介绍如何将普通C++工程生成的头文件和.dll导入到UE中去使用。 步骤 一、新建插件 1. 打开插件浏览器选项卡 2. 打开插件创建器 3. 选择“第三方库”,这里命名为“MyThirdPartyLibrary…...
Type-C双屏显示器方案
在数字化时代,高效的信息处理和视觉体验已成为我们日常生活和工作的关键需求。随着科技的进步,一款结合了便携性和高效视觉输出的设备——双屏便携屏,逐渐崭露头角,成为追求高效工作和娱乐体验人群的新宠。本文将深入探讨双屏便携…...
20250112面试鸭特训营第20天
更多特训营笔记详见个人主页【面试鸭特训营】专栏 250112 1. TCP 和 UDP 有什么区别? 特性TCPUDP连接方式面向连接(需要建立连接)无连接(无需建立连接)可靠性可靠的,提供确认、重传机制不可靠,…...
使用conda出现requests.exceptions.HTTPError 解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
玩转大语言模型——langchain调用ollama视觉多模态语言模型
系列文章目录 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 langchain调用ollama视觉多模态语言模型 系列文章目录前言使用Ollama下载模型查找模型下载模型 测试模型ollama测试langchain测试加载图片加载模型…...
【玩转MacBook】mdfind命令搜索
mdfind 是 macOS 上的一个命令行工具,它允许用户根据元数据来查找文件。mdfind 使用 Spotlight 索引来快速搜索文件系统中的项目。这意味着它可以非常快地找到文件,因为它不直接在磁盘上搜索,而是查询由 Spotlight 维护的索引数据库。 基本用…...
数据结构与算法之二叉树: LeetCode 637. 二叉树的层平均值 (Ts版)
二叉树的层平均值 https://leetcode.cn/problems/average-of-levels-in-binary-tree/description/ 描述 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值与实际答案相差 1 0 − 5 10^{-5} 10−5 以内的答案可以被接受 示例 1 输入:root…...
【巨实用】Git客户端基本操作
本文主要分享Git的一些基本常规操作,手把手教你如何配置~ ● 一个文件夹中初始化Git git init ● 为了方便以后提交代码需要对git进行配置(第一次使用或者需求变更的时候),告诉git未来是谁在提交代码 git config --global user.na…...
从预训练的BERT中提取Embedding
文章目录 背景前置准备思路利用Transformer 库实现 背景 假设要执行一项情感分析任务,样本数据如下 可以看到几个句子及其对应的标签,其中1表示正面情绪,0表示负面情绪。我们可以利用给定的数据集训练一个分类器,对句子所表达的…...
BGP 泄露
大家读完觉得有帮助记得关注和点赞!!! 目录 1. BGP 是什么? 2. 什么是 BGP 泄露? 3. 今天发生了什么? 4. 正常和被劫持状态下的路由示意图 5. 受影响区域 6. 责任在谁? 7. 有办法避免这…...
IntelliJ IDEA和MAVEN基本操作:项目和缓存存储到非C盘
为了将 IntelliJ IDEA 的所有项目和缓存存储到 C 盘以外的地方,以下是你需要调整的设置和步骤: 1. 更改项目默认存储位置 打开 IntelliJ IDEA。点击顶部菜单的 File > Settings (Windows)或 IntelliJ IDEA > Preferences &…...
Leetcode 3418. Maximum Amount of Money Robot Can Earn
Leetcode 3418. Maximum Amount of Money Robot Can Earn 1. 解题思路2. 代码实现 题目链接:3418. Maximum Amount of Money Robot Can Earn 1. 解题思路 这一题我的思路比较暴力,就是一个动态规划,本质上就是全量遍历,然后找到…...
occ的开发框架
occ的开发框架 1.Introduction This manual explains how to use the Open CASCADE Application Framework (OCAF). It provides basic documentation on using OCAF. 2.Purpose of OCAF OCAF (the Open CASCADE Application Framework) is an easy-to-use platform for ra…...
SYS_OP_MAP_NONNULL NULL的等值比较
无意在数据库中发现了这个操作SYS_OP_MAP_NONNULL。 SYS_OP_MAP_NONNULL应该不是数据库中的对象,因为在DBA_OBJECTS中根本找不到它,而在STANDARD和DBMS_STANDARD包中也找不到函数说明。 SQL> SELECT * 2 FROM DBA_OBJECTS 3 WHERE OBJECT_NAME…...
acwing_3196_I‘m stuck
acwing_3196_I’m stuck // // Created by HUAWEI on 2024/11/17. // #include<iostream> #include<cstring> #include<algorithm>using namespace std;const int N 50 5; char g[N][N];// 地图 bool str1[N][N], str2[N][N]; // 判断1,判断2 …...
C++实现设计模式---状态模式 (State)
状态模式 (State) 状态模式 是一种行为型设计模式,它允许对象在运行时根据内部状态的改变来动态改变其行为。通过将状态相关的行为封装到独立的类中,状态模式使得状态的切换更加清晰和灵活。 意图 将对象的行为和状态分离,随着状态的改变动…...
【1】Word:邀请函
目录 题目 文字解析 流程 题目 文字解析 考生文件夹☞Word.docx☞一定要用ms打开,wps打开作答无效☞作答完毕,F12或者手动另存为(考生文件夹:路径文件名) 注意:一定要检查,很有可能你前面步…...
作业(一)
1、shell 脚本写出检测 /tmp/size.log 文件如果存在显示它的内容,不存在则创建一个文件将创建时间写入。 # vim a.sh#!/bin/bash#先对文件/tmp/size.log 是否存在进行判断 if [ -f /tmp/size.log ]; #如果存在,则用cat命令显示文件内容thencat /tmp/…...
[SAP ABAP] APPEND INITIAL LINE 追加空行
语法格式 APPEND INITIAL LINE TO itab.示例1 SFLIGHT(航班) 输出结果: 示例2 我们可以使用下面的语法进行内表分配指针,追加空行并赋值的操作 APPEND INITIAL LINE TO lt_tab ASSIGNING FIELD-SYMBOL(<lfs_val>). REPORT z437_test_2025.* 自…...
Meilisearch ASP.Net Core API 功能demo
安装 MeiliSearch 0.15.5 0.15.5demo code using Meilisearch; using System.Data; using System.Text.Json; using System.Text.Json.Serialization;namespace MeiliSearchAPI {public class MeilisearchHelper{public MeilisearchHelper(){DefaultClient…...
口碑很好的国产LDO芯片,有哪些?
在几乎任何一个电路设计中,都可能会使用LDO(低压差线性稳压器)这个器件。 虽然LDO不是什么高性能的IC,但LDO芯片市场竞争异常激烈。最近几年,诞生了越来越多的精品国产LDO,让人看得眼花缭乱。 业内人士曾经…...
深入浅出C#线程池ThreadPool:提升程序性能的利器
深入浅出C#线程池ThreadPool:提升程序性能的利器 在C#编程中,线程是并发编程的基石,它使我们能够同时执行多个任务,提升程序的响应速度和效率。然而,直接创建和管理线程会带来一定的开销,例如线程创建和销…...
git问题
拉取项目代码后,出现 1、找回未commit的代码 2、记录不全,只是显示部分代码记录...
Code-Server 项目介绍与部署指南
搜索关注,分享更多有趣的知识。 在这里插入图片描述 1. 概述 GitHub: https://github.com/coder/code-server 在日常学习和工作中,Visual Studio Code(VSCode)已成为许多开发者的首选代码编辑器。然而,其…...
NAT技术
NAT技术 1. NAT原理 NAT(Network Address Translation,网络地址转换)是用于在本地网络中使用私有地址,在连接互联网时转而使用全局 IP 地址的技术。NAT实际上是为解决IPv4地址短缺而开发的技术。路由器构建了子网,将…...
pytest 常用插件
pytest 提供了许多功能强大的插件来增强测试体验和执行能力。以下是一些常用的 pytest 插件介绍,并结合 pytest.main() 进行使用的示例。 1. pytest-xdist pytest-xdist 插件用于并行化测试的执行,可以将测试分配到多个 CPU 核心并行运行,从…...
Avalonia 入门笔记(零):概述
Avalonia 是一个基于 .NET 和 Skia 的开源、跨平台 UI 框架,支持 Windows、Linux、macOS、iOS、Android 和 WebAssembly。Skia 是一个基于 C 的开源 2D 渲染引擎,Avalonia 通过 Skia 自绘 UI 控件,保证在全平台具有一致的观感 基于 .NET 的跨…...