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

Linux编译之(1)C语言基础

Linux编译之C语言基础

Author:Once Day Date:2023年3月11日

漫漫长路,才刚刚开始…

1.概述

在Linux下开发多源文件的C代码文件,是一定要了解Makefile的,虽然现在构建工具很多,但学习的一开始,不必追求最新的工具。宜厚积薄发,切勿好高骛远!

首先想象有三个源文件,需要把它们编译成一个源文件,如下:

  • main.c,主要执行逻辑。
  • tool.c,一些辅助工具。
  • debug.c,一些调试工具。

可以如下编译它们:

gcc main.c tool.c debug.c -o main.out

但如果修改了其中的main.c文件,又需要重新编译一次。

不过仅仅只是修改了main.c文件,可以不需要全部重新编译,如下:

gcc -c main.c -o main.o
gcc -c tool.c -o tool.o
gcc -c debug.c -o debug.o
gcc main.o tool.o debug.o -o main.out

在修改了main.c之后,只需要执行以下步骤

gcc -c main.c -o main.o
gcc main.o tool.o debug.o -o main.out

很明显,未修改的文件无需重新编译,C语言是基于文件编译的,这种方式即增量式编译,对于大项目而言(数百上千的源文件),可节约非常多的时间

对于上面的过程,对于修改文件的追踪和指令的输入,能够用模板化的文件指定,即Makefile文件

(Make和Makefile基础语法参考文档:Makefile+Make基础知识_Once_day的博客-CSDN博客)

main: main.o tool.o debug.ogcc -o main main.o tool.o debug.o  #缩进一定要使用tab,不能用空格代替
main.o: main.cgcc -c main.c
tool.o: tool.cgcc -c tool.c
debug.o: debug.cgcc -c debug.c

为什么依赖关系写得这么多?因为充足的依赖关系才能让Make等工具自动识别哪些文件需要重编译,哪些则不需要。一个常见的增量式编译问题就是,文件修改了,一部分文件重启编译,一部分没有,导致编译完成,但功能非常异常

如果将缩进的TAB符换成了空格,make工具会提示missing separator错误。

1.2 使用makefile自动化变量

在上述的Makefile编写里面,把所有文件都写出来了,这个对于大量文件来说,很不现实。可以使用Makefile变量语法。

首先可以定义变量:

A = once
b = $(A)
c := $(A)
d ?= D
A = dayshow:echo $(b) $(c) $(d)

有三种赋值方式,结果如下:

  • =赋值,类似引用,所以b的值为day,即A的最后有效值。
  • :=赋值,类似于值赋值,所以c的值为once,仅使用赋值之前的A值。
  • ?=赋值,尝试性赋值,如果d的值不为空(完全空,空字符串不算),那么赋值为D.

因此将所有的目标文件赋值到变量上:

objects = main.o tool.o debug.o
main : $(objects)gcc -o main $(objects)%.o : %.cgcc -c $<

下面的%.o等是模式匹配,即匹配所有后缀为.o的文件,$<是和模式匹配相对应的自动化变量,其代表了一类由模式匹配定义的文件集合。

在这里$<表示符合%.c定义的所有文件集合,即main.c tool.c debug.c,这样就无须手动输入文件名字。

1.3 伪目标
.PHONY : cleanclean:rm *.o

如上所示,.PHONY后面表示的是伪目标。对于伪目标,不用和真实的文件产生关联,当每次输入伪目标时,总是会执行该目标下命令。

2.交叉编译环境

随着开发环境的改变,需要在常见的X86平台上编译出能在ARM上运行的程序,这就是常见的交叉编译环境。可以直接使用ARM官方提供的工具链,也可以使用打包好的开发工具(apt-get)等下载。

  • Arm GNU Toolchain Downloads – Arm Developer
  • Ubuntu20.04配置交叉编译环境arm-linux-gcc_apt-get install arm-linux_蜻蜓队长~的博客-CSDN博客

编译器选择合适设备的即可,一般如下命名:

arm-none-linux-gnueabihf
arm-none-eabi
aarch64-none-elf
  • arm是指定的架构,即ARM系列CPU,aarch64是64位架构。
  • none这里是厂家指定的名字,这是ARM官方的,因此为none
  • ebai是嵌入式API接口的意义。
  • hf是带有硬件浮点数,代码会使用浮点指令。
  • linux-gnu指定平台,这个并非裸机开发接口,默认在Linux-gnu平台跑。

在ubuntu下(需要换源)可以直接安装编译环境,但是版本会是最新的。

使用apt search arm-linuxapt search aarch64-linux分别查看32位和64位编译器(c,c++,go等)。

ubuntu系统可能需要换源,需要去国内源网站寻找合适的列表:

  • LUG’s repo file generator (ustc.edu.cn)
  • ubuntu换镜像源(ubuntu换源)_Fighting_1997的博客-CSDN博客

根据需要可下载指定的编译器:

sudo apt install gcc-aarch64-linux-gnu		#64位
sudo apt install gcc-arm-linux-gnueabihf	#32位

如下所示:

ubuntu->c-code:$ aarch64-linux-gnu-gcc symbol.c -o test64.out
ubuntu->c-code:$ file test64.out 
test64.out: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=14313c53139a32bb1ad71e60439816744e04faab, for GNU/Linux 3.7.0, not stripped
2.1 在本地机器和远程编译服务器上传入内容

在远程交叉服务器上可以使用SCP来传输文件,远程服务器要开启stfp-server功能,将本地设备的rsa公钥放在服务器上即可。如下:

  • ssh-keygen -t rsa -C "local-z3200",生成私钥和公钥,放在本地机器的合适位置。
  • 将公钥(id_rsa.pub)内容复制到远程服务器的/home/username/.ssh/authorized_keys 文件中。
  • 然后使用scp命令传输。

SCP命令可参考:Linux scp命令 | 菜鸟教程 (runoob.com).

usage: scp [-346ABCOpqRrsTv] [-c cipher] [-D sftp_server_path] [-F ssh_config][-i identity_file] [-J destination] [-l limit][-o ssh_option] [-P port] [-S program] source ... target

简单参数如下:

  • -1: 强制scp命令使用协议ssh1
  • -2: 强制scp命令使用协议ssh2
  • -4: 强制scp命令只使用IPv4寻址
  • -6: 强制scp命令只使用IPv6寻址
  • -B: 使用批处理模式(传输过程中不询问传输口令或短语)
  • -C: 允许压缩。(将-C标志传递给ssh,从而打开压缩功能)
  • -p:保留原文件的修改时间,访问时间和访问权限。
  • -q: 不显示传输进度条。
  • -r: 递归复制整个目录。
  • -v:详细方式显示输出。scp和ssh(1)会显示出整个过程的调试信息。这些信息用于调试连接,验证和配置问题。
  • -c cipher: 以cipher将数据传输进行加密,这个选项将直接传递给ssh。
  • -F ssh_config: 指定一个替代的ssh配置文件,此参数直接传递给ssh。
  • -i identity_file: 从指定文件中读取传输时使用的密钥文件,此参数直接传递给ssh。
  • -l limit: 限定用户所能使用的带宽,以Kbit/s为单位。
  • -o ssh_option: 如果习惯于使用ssh_config(5)中的参数传递方式,
  • -P port:注意是大写的P, port是指定数据传输用到的端口号
  • -S program: 指定加密传输时所使用的程序。此程序必须能够理解ssh(1)的选项。

一般使用下面形式即可:

scp -i /var/flow-info/id_rsa source_file destination_file

如果目标文件位置在本机,那就是从服务器下载,如果目标位置在服务器,那就是上传文件。

scp -i /var/flow-info/id_rsa root@onceday.work:/home/ubuntu/c-code/test64.out test.out

上面即从远程服务器下载文件到本地机器上,root是用户名,密钥需要和用户名对应上。

2.2 使用交叉编译器进行编译
ubuntu->c-code:$ aarch64-linux-gnu-gcc-11 symbol.c -o test64.out 

使用对应的执行程序即可。交叉编译器一般都有前缀来修饰,如下:

ubuntu->aarch64-linux-gnu:$ ll
total 20
drwxr-xr-x  5 root root 4096 Mar 12 15:52 ./
drwxr-xr-x 16 root root 4096 Mar 12 15:52 ../
drwxr-xr-x  2 root root 4096 Mar 12 15:52 bin/
drwxr-xr-x 32 root root 4096 Mar 12 15:52 include/
drwxr-xr-x  2 root root 4096 Mar 12 16:59 lib/

编译时,各类可执行文件(gcc, ar, ld等等),头文件(include),以及lib都放在了指定目录下

不同的交叉编译器会生成不同的版本,因此需要根据实际需求来翻找目录。

将上列编译的二进制程序放在本地设备上运行,很大概率会出现以下错误:

onceday->shell:# ./test.out
./test.out: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by ./test.out)

这是因为编译服务器上的glibc版本较高导致的。解决该问题有多种方式,可参考:

  • glibc 下载及编译_glibc下载_kalaneryok的博客-CSDN博客
  • [glibc编译小记 | Marvin’s Blog【程式人生】 (marvinsblog.net)](https://marvinsblog.net/post/2019-02-12-compile-glibc/#:~:text=可以尝试使用下面的命令来指定glibc(之前编译的版本): gcc glibc-version.c -Wl%2C–rpath %3D%24HOME %2Fglibc%2F2.23%2Flib -Wl%2C–dynamic-linker %3D%24HOME,-rpath-link 的方法,在 Re%3A Linking against different glibc version%3F)
  • 【gcc】高版本gcc编译出的程序在低版本glibc机器上运行_高版本gcc编译 低版本运行_bandaoyu的博客-CSDN博客
  • 低版本 libc 中运行高本版 libc 库链接的程序_patchelf chroot_longyu_wlz的博客-CSDN博客
  • 多个gcc/glibc版本的共存及指定gcc版本的编译_gcc编译指定glibc版本_mo4776的博客-CSDN博客

解决方法很多,最常见的有以下几种:

  • 升级本机设备的GLIBC版本,可行程度一般。
  • 修改可执行程序的设置,改变动态库加载地方和GLIBC库引用地方,这个相当于整体打包静态库一起发布,程序使用自身的库,可行程度较高。
  • 自行编译合适版本GLIBC库,然后用于编译,步骤较为麻烦,但效果应该做好。
  • 各种骚操作修改编译过程和二进制指令,不太推荐,适合于特殊情况。

接下来介绍两种方式,即修改动态库加载地址(默认地址是/usr/lib,这个是系统默认的库,不能改动,需要放在其他地方),以及编译指定版本的glibc库。

2.3 修改可执行目标文件中的动态库解析器指向的位置

有多种方式,如patchelf工具可以直接修改,首先安装该工具:

apt-get install patchelf

常见命令如下:

ubuntu->aarch64-linux-gnu:$ patchelf
syntax: patchelf[--set-interpreter FILENAME][--print-interpreter][--set-rpath RPATH][--add-rpath RPATH][--remove-rpath][--print-rpath]FILENAME...

这里主要使用下面两个命令:

patchelf --set-rpath /my/lib your_program
patchelf --set-interpreter /my/lib/ld-linux.so.2 your_program

路径可以使用绝对路径和相对路径两种。

如下所示,现在程序可以正常运行了(使用./lib库中的动态链接文件)。

onceday->shell:# ll lib/
total 1792
drwxr-xr-x 2 root root    4096 Mar 12 18:07 ./
drwxr-xr-x 3 root root    4096 Mar 12 18:00 ../
-rwxr-xr-x 1 root root  182488 Mar 12 18:07 ld-linux-aarch64.so.1*
-rw-r--r-- 1 root root     317 Mar 12 18:00 libc.so
-rw-r--r-- 1 root root 1635112 Mar 12 18:00 libc.so.6
onceday->shell:# file test.out
test.out: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter ./lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=14313c53139a32bb1ad71e60439816744e04faab, not stripped

除了使用patchelf工具改变ELF头信息之外,还可以编译时加入参数来更改

# 绝对路径
gcc -Wl,-rpath='/my/lib',-dynamic-linker='/my/lib/ld-linux.so.2'
  • -Wl,传递后面的选项到链接器中,ELF头信息的最终修改是在链接阶段落幕的。
  • -rpath=dir,指定动态库链接的文件目录,即指定的文件目录。
  • -dynamic-linker=dir,指定动态链接器的名字。

这两个参数分别设置的elf文件中的rpath和interpreter字段。

rpath,全名run-time search path,是elf文件中一个字段,它指定了可执行文件执行时搜索so文件的第一优先位置,一般编译器默认将该字段设为空。elf文件中还有一个类似的字段runpath,其作用与rpath类似,但搜索优先级稍低。搜索优先级:

rpath > LD_LIBRARY_PATH > runpath > ldconfig缓存 > 默认的/lib,/usr/lib等

可以指定相对路径,如下,ld会将ORIGIN理解成可执行文件所在的路径:

gcc -Wl,-rpath='$ORIGIN/../lib'

下面是一个实例(-Wl中W大写):

ubuntu->c-code:$ aarch64-linux-gnu-gcc-11 -Wl,-rpath='./lib',-dynamic-linker='./lib/ld-linux-aarch64.so.1' symbol.c -o test64.out
ubuntu->c-code:$ patchelf --print-interpreter test64.out 
./lib/ld-linux-aarch64.so.1

可以看到,链接的动态库位置和链接器已经是预定目录了,然后打包程序的时候,按照需要打包动态库文件即可

2.4 编译指定版本的glibc库文件
  • glibc库的交叉编译及使用_yebanguhe的博客-CSDN博客
  • glibc 下载及编译_glibc下载_kalaneryok的博客-CSDN博客

首先使用ldd查看本地设备(目标设备)的glibc版本,如下:

onceday->shell:# ldd --version
ldd (GNU libc) 2.27
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

可以看到版本为2.27,然后去官网下载对应版本的源码压缩包即可。

  • http://ftp.gnu.org/pub/gnu/glibc/ 官方下载,速度有点慢,可以使用代理加加速。
  • https://downloads.uclibc-ng.org/releases/,uclibc的下载点,另外一个libc库的选择。

在本地设备上通过代理下载好了以后,可以使用scp传输到远程设备上

PS D:\mysoft> scp .\glibc-2.27.tar.gz ubuntu@onceday.work:/home/ubuntu/  

解压命令为tar -zxv -f glibc-2.27.tar.gz ,其他压缩格式需要修改对应的z字符为jJ

glibc库不能在所在目录中编译输出,需要额外创建目录,这里选在/usr/glibc2.27:

sudo mkdir /usr/glibc2.27
sudo chmod 777 /usr/glibc2.27

需要安装一些依赖库,如下:

apt install make
apt install gawk
apt install texinfo
apt install gettext
apt install gcc-12-aarch64-linux-gnu
apt install g++-12-aarch64-linux-gnu
apt install bison

可查看INSTALL文件,里面详细描述了如何编译和安装glibc库,必须具备完整的编译环境,一般而言,前面的交叉环境会搞定这个事情,然后如下即可:

../glibc-2.27/configure \--prefix=/usr/glibc2.27/output \CC=aarch64-linux-gnu-gcc-12 \CXX=aarch64-linux-gnu-g++-12\NM=aarch64-linux-gnu-gcc-nm-12\READELF=aarch64-linux-gnu-readelf\--host=aarch64-ntos-linux-gnu \--build=x86_64-none-linux-gnu \--with-headers=/usr/aarch64-linux-gnu/include \--enable-kernel=4.14.0 \--with-binutils=/usr/aarch64-linux-gnu/bin \--disable-werror
  • --prefix=,指定目标安装文件夹,需要注意,默认将安装到/usr/local,这会导致不好的后果,切记指定一个其他目录。
  • CC=\CXX=,指定编译器,这里需要指定交叉编译器,即aarch64-linux-gnu-gcc-11
  • --build=,指定编译环境的本地系统,即用于编译的机器。
  • --host=,指定目标运行系统,即本地设备类型,命名规则可在glibc源码的readme文件中查看。
  • --with-headers,交叉编译需要使用目标系统上的Linux头文件。
  • --enable-kernel=4.14.0,指定最小运行版本号,这是针对Linux系统设置的。
  • --with-binutils=,使用指定的二进制工具包,即交叉编译所携带的工具。
  • --disable-werror,跳过小错误,由于glibc版本和编译器版本不对应,有一些正常报错,可以忽略。

开启编译,使用make -j 4,表示使用多核编译,加快速度。

编译成功后,需要make install生成目标安装文件,然后打包output里面的文件,就是一个完整的glibc库了。

2.5 使用本地编译的glibc库来做开发

和使用默认开发路径的glibc库不同,本地编译的glibc库需要分开多部编译。

第一步是首先使用头文件和源文件生成目标文件:

aarch64-linux-gnu-gcc-11 -I~/include sybmol.c -o test2.o

这里~/include即使本地编译的glibc库include目录。

然后链接动态加载器和标准C库,即如下:

aarch64-linux-gnu-gcc-11 test2.o ../lib/libc.so.6 ../lib/ld-linux-aarch64.so.1 -o test3.out

这样生成的可执行程序便是我们指定glibc版本的可执行程序

(整个开发过程问题很多,难以详细写出,有问题可以留言,一起讨论)

相关文章:

Linux编译之(1)C语言基础

Linux编译之C语言基础 Author&#xff1a;Once Day Date&#xff1a;2023年3月11日 漫漫长路&#xff0c;才刚刚开始… 1.概述 在Linux下开发多源文件的C代码文件&#xff0c;是一定要了解Makefile的&#xff0c;虽然现在构建工具很多&#xff0c;但学习的一开始&#xff0…...

CPU平均负载高问题定位分析

一、Linux操作系统CPU平均负载 1.1什么是CPU平均负载 1.2 怎么查看平均负载数值 二、Linux操作系统CPU使用率和平均负载区别 CPU使用率和平均负载区别 三、阿里云Linux操作系统CPU压测环境准备 3.1 核心命令应用场景 3.2 模拟生产环境出现的多种问题环境准备 分析工具安…...

Python蓝桥杯训练:基本数据结构 [二叉树] 中

Python蓝桥杯训练&#xff1a;基本数据结构 [二叉树] 中 文章目录Python蓝桥杯训练&#xff1a;基本数据结构 [二叉树] 中一、[翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/)二、[对称二叉树](https://leetcode.cn/problems/symmetric-tree/)三、[二叉树的最…...

读取 DTC 信息服务 (0x19) – UDS 协议

总目录链接>> AutoSAR入门和实战系列总目录 0x19读取 DTC 信息服务概述 读取 DTC 信息服务在 UDS 协议中用于从车辆或特定 ECU 或节点读取 DTC。UDS 协议的主要任务之一是故障诊断。每当车辆发生任何故障时&#xff0c;与该故障相对应的诊断故障代码&#xff08;DTC&a…...

Hive 分区表新增字段 cascade

背景 在以前上线的分区表中新加一个字段&#xff0c;并且要求添加到指定的位置列。 模拟测试 加 cascade 操作 创建测试表 create table if not exists sqltest.table_add_column_test(org_col1 string comment 原始数据1,org_col2 string comment 原始数据2 ) comment 增…...

【Java版oj】day08两种排序方法、最小公倍数

目录 一、两种排序方法 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 二、最小公倍数 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 一、两种…...

FinOps,从概念到落地 | UGeek大咖说第一期直播回顾(上)

2023年2月28日&#xff0c;由优维科技联合FinOps产业推进方阵举办了第1期「UGeek大咖说-极致用云共济FinOps」线上直播活动&#xff0c;来自中国信通院及美图公司技术专家共同带来了一场精彩的技术视听盛宴。 直 播 背 景 目前&#xff0c;许多以“上云”为数字化转型路径的企…...

k8s java程序实现kubernetes Controller Operator 使用CRD 学习总结

k8s java程序实现kubernetes Controller & Operator 使用CRD 学习总结 大纲 原理Controller 与 Operator自定义资源定义 CRD ( CustomResourceDefinition)kubernetes-client使用java fabric8io/kubernetes-client操作k8s 原生资源使用java abric8io/kubernetes-clientt操…...

Unity笔记:修改代码执行的默认打开方式

使用 External Tools 偏好设置可设置用于编写脚本、处理图像和进行源代码控制的外部应用程序。 External Script Editor&#xff1a;选择 Unity 应使用哪个应用程序来打开脚本文件。Unity 会自动将正确的参数传递给内置支持的脚本编辑器。Unity 内置支持 Visual Studio Commun…...

Linux IPC:匿名管道 与 命名管道

目录一、管道的理解二、匿名管道三、命名管道四、管道的通信流程五、管道的特性进程间通信方式有多种&#xff0c;本文介绍的是管道&#xff0c;管道分为匿名管道和命名管道。 一、管道的理解 生活中的管道用来传输资源&#xff0c;例如水、石油之类的资源。而进程间通信的管道…...

阿里研发工程师JAVA暑期实习一面

文章目录先说一下我自己的情况面试过程总结先说一下我自己的情况 我就读于湖南大学&#xff0c;软件工程专业&#xff0c;现在大三下 很巧的是&#xff0c;我在大二的时候就在相同的时间面过相同的部门和相同的岗位&#xff0c;所以我没有做笔试就直接让我去面试了。我当时还纳…...

第十四届蓝桥杯三月真题刷题训练——第 11 天

目录 第 1 题&#xff1a;卡片 题目描述 运行限制 第 2 题&#xff1a;路径_dpgcd 运行限制 第 3 题&#xff1a;字符统计 问题描述 输入格式 输出格式 样例输入 样例输出 评测用例规模与约定 运行限制 第 4 题&#xff1a;费用报销 第 1 题&#xff1a;卡片 题…...

机器学习入门——线性回归

线性回归什么是线性回归&#xff1f;回归分析&#xff1a;线性回归&#xff1a;回归问题求解单因子线性回归简单实例评估模型表现可视化模型展示多因子线性回归什么是线性回归&#xff1f; 回归分析&#xff1a; 根据数据&#xff0c;确定两种或两种以上变量间相互依赖的定量…...

Microsoft Word 远程代码执行漏洞(CVE-2023-21716)

本文转载于&#xff1a; https://mp.weixin.qq.com/s?__bizMzI5NTUzNzY3Ng&mid2247485476&idx1&sneee5c7fd1c4855be6441b8933b10051e&chksmec535547db24dc516d013d3d76097e985aaad7f10f82f15b4e355a97af75fd333acdab6232af&mpshare1&scene23&srci…...

Android kotlin 系列讲解(数据篇)SharedPreferences存储及测试

文章目录 一、什么是SharedPreferences1、将数据存储到SharedPreferences中2、从SharedPreferences中读取数据二、登录使用SharedPreferences一、什么是SharedPreferences SharedPreferences是使用键值对的方式来存储数据的。也就是说,当保存一条数据的时候,需要给这条数据提…...

一文了解Web Worker

一、概述 众所周知&#xff0c;JavaScript最初设计是运行在浏览器中的&#xff0c;为了防止多个线程同时操作DOM带来的渲染冲突问题&#xff0c;所以JavaScript执行器被设计成单线程。但是随着前端技术的发展&#xff0c;JavaScript要处理的工作也越来越复杂&#xff0c;当我们…...

接口文档包含哪些内容?怎么才能写好接口文档?十年测试老司机来告诉你

目录 接口文档结构 参数说明 示例 错误码说明 语言基调通俗易懂 及时更新与维护 总结 那么我们该如何写好一份优秀的接口文档呢&#xff1f; 接口文档结构 首先我们要知道文档结构是什么样子的。接口文档应该有清晰明确的结构&#xff0c;以便开发人员能快速定位自己需…...

java面试八股文之------Java并发夺命23问

java面试八股文之------Java并发夺命23问&#x1f468;‍&#x1f393;1.java中线程的真正实现方式&#x1f468;‍&#x1f393;2.java中线程的真正状态&#x1f468;‍&#x1f393;3.如何正确停止线程&#x1f468;‍&#x1f393;4.java中sleep和wait的区别&#x1f468;‍…...

CANoe中使用CAPL刷写流程详解(Trace图解)(CAN总线)

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…...

【MySQL】002 -- 日志系统:一条SQL更新语句是如何执行的

此文章为《MySQL 实战 45 讲》的学习笔记&#xff0c;其课程链接可参见&#xff1a;MySQL实战45讲_MySQL_数据库-极客时间 目录 一、日志系统 1、重做日志&#xff1a;redo log&#xff08;引擎层&#xff09; 2、归档日记&#xff1a;binlog&#xff08;Server层&#xff09; …...

C++---背包模型---数字组合(每日一道算法2023.3.14)

注意事项&#xff1a; 本题是"动态规划—01背包"的扩展题&#xff0c;优化思路不多赘述&#xff0c;dp思路会稍有不同&#xff0c;下面详细讲解。 题目&#xff1a; 给定 N个正整数 A1,A2,…,AN&#xff0c;从中选出若干个数&#xff0c;使它们的和为 M&#xff0c;…...

并查集(不相交集)详解

目录 一.并查集 1.什么是并查集 2.并查集的基本操作 3.并查集的应用 4.力扣上的题目 二.三大操作 1.初始化 2.查找 3.合并 三.省份数量 1.题目描述 2.问题分析 3.代码实现 四.冗余连接 1.题目描述 2.问题分析 3.代码实现 一.并查集 1.什么是并查集 并查集&…...

10个最频繁用于解释机器学习模型的 Python 库

文章目录什么是XAI&#xff1f;可解释性实践的步骤技术交流1、SHAP2、LIME3、Eli54、Shapash5、Anchors6、BreakDown7、Interpret-Text8、aix360 (AI Explainability 360)9、OmniXAI10、XAI (eXplainable AI)XAI的目标是为模型的行为和决定提供有意义的解释&#xff0c;本文整理…...

final关键字:我偏不让你继承

哈喽&#xff0c;小伙伴们大家好&#xff0c;我是兔哥呀&#xff0c;今天就让我们继续这个JavaSE成神之路&#xff01; 这一节啊&#xff0c;咱们要学习的内容是Java所有final关键字。 之前呢&#xff0c;我们学习了继承&#xff0c;这大大提高了代码的灵活性和复用性。但是总…...

8大主流编程语言的适用领域,你可能选错了语言

很多人学编程经常是脑子一热然后就去网上一搜资源就开始学习了&#xff0c;但学到了后面发现目前所学的东西并不是自己最喜欢的&#xff0c;好像自己更喜欢另一个技术&#xff0c;感觉自己学错了&#xff0c;于是乎又去学习别的东西。 结果竹篮打水一场空&#xff0c;前面所付…...

关于Python库的问题

关于Python库的问题 问题1&#xff1a; ModuleNotFoundError: No module named ‘requests’ Python库 Pycharm使用Requests库时报错&#xff1a; No module named requests’解决方法 未安装requests库&#xff0c;使用"pip install requests"命令安装 依然提示P…...

好记性不如烂笔头(2)

概述&#xff1a;用来记录一些小技巧。 1.查看MyBatis执行的sql 类&#xff1a;org.apache.ibatis.mapping.MappedStatement方法&#xff1a;getBoundSql(Object parameterObject)在IDEA的Evaluate Expression查看sql&#xff1a;boundSql.getSql() 2.maven仓库地址为https&…...

Java for循环嵌套for循环,你需要懂的代码性能优化技巧

前言 本篇分析的技巧点其实是比较常见的&#xff0c;但是最近的几次的代码评审还是发现有不少兄弟没注意到。 所以还是想拿出来说下。 正文 是个什么场景呢&#xff1f; 就是 for循环 里面还有 for循环&#xff0c; 然后做一些数据匹配、处理 这种场景。 我们结合实例代码来…...

关于我拒绝了腾讯测试开发岗offer这件事

2022年刚开始有了向要跳槽的想法&#xff0c;之前的公司不能算大厂但在重庆也算是数一数二。开始跳槽的的时候我其实挺犹豫的 其实说是有跳槽的想法在2022年过年的时候就有了&#xff0c;因为每年公司3月会有涨薪的机会&#xff0c;所以想着看看那能不能涨&#xff08;其实还是…...

从GPT到GPT-3:自然语言处理领域的prompt方法

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…...

wordpress个人电脑搭建/代写文案的软件

模型/视图编程 模型/视图编程简介 Qt包含一组项目视图类&#xff0c;这些项目视图类使用模型/视图架构来管理数据及其向用户呈现方式之间的关系。此体系结构引入的功能分离为开发人员提供了更大的灵活性&#xff0c;可以自定义项目的表示形式&#xff0c;并提供标准的模型界面&…...

网页布局方式/深圳seo优化外包公司

【填空题】在JSP中实现动态刷新页面可以使用方法。【判断题】两个列车互相交会,叫做会车;先到的列车在本站停车,等待后一个同方向的列车通过本站或到达本站停车后先开,叫做越行。【单选题】()装置是用外力迫使运行中机车车辆减速或停车的一种设备。【填空题】()是用不同颜色灯光…...

营销网站建设评估及分析/百度网址大全首页链接

目录 1.视图对象 1.1创建视图 1)简单视图 2&#xff09;建立只读视图 3&#xff09;复杂视图 1.2管理视图 1&#xff09;查看视图定义 2&#xff09;修改视图定义 3&#xff09;重新编译视图 4&#xff09;删除视图 2.索引 2.1索引概述 2.2创建索引 1&#xff09…...

网站如何做se/今日十大头条新闻

类加载所有类加载器&#xff0c;都是ClassLoader的子类。类加载器永远以.class运行的目录为准。读取classpath根目录下的文件有以下几种方式&#xff1a;1 在Java项目中可以通过以下方式获取classspath下的文件&#xff1a;public void abc(){//每一种读取方法,使用某个类获取A…...

tk后缀网站是什么网站/东莞今天发生的重大新闻

上一次自己写了一个多线程断点续传下载的demo&#xff0c;过于麻烦&#xff0c;bug超多&#xff0c;所以我学习使用xutils来完成此功能。 先将xutils依赖搭建好&#xff08;上一篇博客已经具体写了方法&#xff09; 先看看效果图&#xff1a; 下面开始代码的逻辑&#xff1a; 在…...

做网站源代码/成都seo论坛

通过kmeans分析出租车数据并进行可视化&#xff08;1&#xff09;数据准备&#xff08;2&#xff09;创建dataframe&#xff08;3&#xff09;kmeans聚类分析&#xff08;4&#xff09;调用百度API进行数据可视化&#xff08;1&#xff09;数据准备 采用数据为出租车载客时的G…...