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

Linux之基础开发工具二(makefile,git,gdb)

目录

一、自动化构建-make/makefile

1.1、背景

1.2、基本使用

1.3、推导过程

1.4、语法拓展

二、进度条小程序

2.1、回车与换行

2.2、行缓冲区

2.3、练手-倒计时程序

2.4、进度条程序

三、版本控制器-Git

3.1、版本控制器

3.2、gitee的使用

3.2.1、如何创建仓库

3.2.2、如何将仓库克隆到本地

3.2.3、gitee三板斧

3.2.4、git pull

四、调试器-gdb/cgdb

4.1、预备

4.2、常见使用

4.3、常见技巧

4.3.1、watch

4.3.2、set var 确定问题原因

4.3.3、条件断点


一、自动化构建-make/makefile

1.1、背景

  • 会不会写makefile,从⼀个侧⾯说明了⼀个⼈是否具备完成⼤型⼯程的能⼒。
  • ⼀个⼯程中的源⽂件不计数,其按类型、功能、模块分别放在若⼲个⽬录中,makefile定义了⼀系列的规则来指定,哪些⽂件需要先编译,哪些⽂件需要后编译,哪些⽂件需要重新编译,甚⾄于进⾏更复杂的功能操作。
  • makefile带来的好处就是⸺“⾃动化编译”,⼀旦写好,只需要⼀个make命令,整个⼯程完全 ⾃动编译,极⼤的提⾼了软件开发的效率。
  • make是⼀个命令⼯具,是⼀个解释makefile中指令的命令⼯具,⼀般来说,⼤多数的IDE都有这个命令,⽐如:Delphi 的 make,Visual C++ 的nmake,Linux 下 GNU 的 make。可⻅,makefile 都成为了⼀种在⼯程⽅⾯的编译⽅法。
  • make是⼀条命令,makefile是⼀个⽂件,两个搭配使⽤,完成项⽬⾃动化构建。

1.2、基本使用

示例代码:

makefile文件:

使用:

注释:在makefile文件中使用 # 进行注释。

依赖关系:

proc:proc.c 这一行叫做依赖关系,冒号右边的叫做依赖文件列表,依赖文件列表可以有一个或多个文件,也可以有零个文件,如 clean 这一行,它也是一行依赖关系,但它的依赖文件列表中没有文件。

依赖方法:

依赖关系下面缩进的部分就是依赖方法,表示执行依赖关系时执行的方法/指令,它必须以一个tab开头。gcc -o proc proc.c 和 rm -f proc 都是依赖方法。一个依赖关系下面可以有多行依赖方法,但都要以一个tab开头。依赖方法可以是任意指令。如图:

伪目标:

.PHONY表示声明一个伪目标,冒号后面跟伪目标的名称,需要执行它的依赖方法时只需要 make + 伪目标名称即可。.PHONY的作用是让被修饰的目标文件对应的方法总是被执行的。

makefile/make原理:

  1. makefile文件会被make从上向下扫描,第一个目标名是缺省形成的,即执行第一个依赖关系的方法时只需要make命令就行,但如果我们想执行其他组的依赖关系和依赖方法,需要make + 目标名。
  2. make,makefile在执行gcc命令时,如果发生了语法错误,就会终止推导过程。
  3. make解释makefile的时候,是会自动推导的。一直推导,推导过程,不执行依赖方法。直到推导到有依赖文件存在,然后再逆向的执行所有的依赖方法。
  4. make默认只形成一个可执行程序。

取消回显:

默认情况下,我们使用make命令时会回显依赖方法,如图:

  • makefile文件:

  • 使用:

想要取消回显,我们只需要在依赖方法前加@符号,如图:

  • makefile文件:

  • 使用:

项目清理:

  • ⼯程是需要被清理的。
  • 像clean这种,没有被第⼀个⽬标⽂件直接或间接关联,那么它后⾯所定义的命令将不会被⾃动执⾏,不过,我们可以显⽰要make执⾏。即命令⸺“make clean”,以此来清除所有的⽬标 ⽂件,以便重编译。
  • 但是⼀般我们这种clean的⽬标⽂件,我们将它设置为伪⽬标,⽤ .PHONY 修饰,伪⽬标的特性是,总是被执⾏的。

什么叫做总是被执行:

我们看下面示例

  • makefile文件:

  • 效果:

  • makefile文件:

  • 效果:

从上面两组示例可以看出,只有当编译指令所在的依赖关系被.PHONY修饰后,才能每次make都成功,这是为什么呢?其实,无论源文件还是最终生成的可执行文件本质都是文件,只要是文件就会有时间属性,如图:

上图中Access是文件最近被访问的时间,Modify是文件内容最近被修改的时间,Change是文件属性最近被修改的时间。决定一个文件是否需要被重新编译的是Modify时间,源文件和可执行程序都有自己的Modify时间,我们通过make执行编译命令时,它会自动对比这两个文件的Modify时间,如果可执行程序的时间新,就说明没有必要重新编译,也就如上面示例所示,编译命令不会执行,如果源文件的时间新,那就说明需要重新编译生成新的可执行程序,make命令就会成功,所以当我们不加.PHONY时,make命令成功与否取决于这两个时间的比较,而加上.PHONY后,make命令就会忽略时间的比较,直接去执行。

注意:有些命令需要比较时间,而有些命令本身就和时间无关,这些和时间无关的命令加不加.PHONY修饰都一样,但有些时候依赖方法有很多命令,只要有和时间有关的,就可能需要.PHONY修饰。

结论:

  • .PHONY:让make忽略源⽂件和可执⾏⽬标⽂件的M时间对⽐。

1.3、推导过程

下面我们看一下myproc.c生成myproc的完整推导过程:

myproc:myproc.o

        gcc myproc.o -o myproc

myproc.o:myproc.s

        gcc -c myproc.s -o myproc.o

myproc.s:myproc.i

        gcc -S myproc.i -o myproc.s

myproc.i:myproc.c

        gcc -E myproc.c -o myproc.i

.PHONY:clean

clean:

        rm -f *.i *.s *.o myproc

编译图解:

make是如何⼯作的,在默认的⽅式下,也就是我们只输⼊make命令。那么:

  1. make会在当前⽬录下找名字叫“Makefile”或“makefile”的⽂件。
  2. 如果找到,它会找⽂件中的第⼀个⽬标⽂件(target),在上⾯的例⼦中,他会找到 myproc 这个⽂件,并把这个⽂件作为最终的⽬标⽂件。
  3. 如果myproc⽂件不存在,或是myproc所依赖的后⾯的 myproc.o ⽂件的⽂件修改时间要比myproc 这个⽂件新(可以⽤ touch 测试),那么,他就会执⾏后⾯所定义的命令来⽣成myproc 这个⽂件。
  4. 如果 myproc 所依赖的 myproc.o ⽂件不存在,那么 make 会在当前⽂件中找⽬标为myproc.o ⽂件的依赖性,如果找到则再根据那⼀个规则⽣成 myproc.o ⽂件。(这有点像⼀个堆栈的过程)
  5. 如果.o文件不存在,它会继续找生成.o文件所需的依赖文件,然后看该文件是否存在,如果存在就执行依赖方法生成,如果不存在则继续查找该文件的依赖文件。
  6. 在这个逐层查找的过程中,每找一层就会将它们的方法入栈,直到找到某一个依赖文件存在时,该依赖关系对应的依赖方法也进栈,之后就可以开始出栈了。
  7. 这就是整个make的依赖性,make会⼀层⼜⼀层地去找⽂件的依赖关系,直到最终编译出第⼀个⽬标⽂件。
  8. 在找寻的过程中,如果出现错误,⽐如最后被依赖的⽂件找不到,那么make就会直接退出,并报错,⽽对于所定义的命令的错误,或是编译不成功,make根本不理。
  9. make只管⽂件的依赖性,即,如果在我找了依赖关系之后,冒号后⾯的⽂件还是不在,那么对不起,我就不⼯作啦。

注意:上面这种写法太麻烦了,实践中一般不会这么写,一般只生成.o文件和可执行文件。

1.4、语法拓展

  • 变量:在makefile文件中可以定义变量,且变量没有类型。语法:变量名= ... 。
  • $(变量名):使用定义好的变量。
  • %:makefile文件中的通配符。
  • $<:把依赖文件依次放入指令中,放入一个执行一次指令。
  • $^:把依赖文件一次全部放入指令中,然后执行指令(只执行一次)。
  • $@:表示依赖关系中冒号左侧的内容。
  • @:取消指令回显

示例如下:

BIN=proc.exe                 # 定义变量

CC=gcc

#SRC=$(shell ls *.c)         # 采⽤shell命令⾏⽅式,获取当前所有.c⽂件名

SRC=$(wildcard *.c)         # 或者使⽤ wildcard 函数,获取当前所有.c⽂件名

OBJ=$(SRC:.c=.o)          # 将SRC的所有同名.c 替换 成为.o 形成⽬标⽂件列表

LFLAGS=-o                     # 链接选项

FLAGS=-c                       # 编译选项

RM=rm -f                         # 引⼊命令

$(BIN):$(OBJ)

        @$(CC) $(LFLAGS) $@ $^         # $@:代表⽬标⽂件名。 $^: 代表依赖⽂件列表

        @echo "linking ... $^ to $@ "

%.o:%.c                                        # %.c 展开当前⽬录下所有的.c。 %.o: 同时展开同名.o

        @$(CC)  $(FLAGS)  $<           # %对展开的依赖.c⽂件,⼀个⼀个的交给gcc。

        @echo "compling ... $< to $@ "         # @:不回显命令

.PHONY:clean

clean:

        $(RM) $(OBJ) $(BIN)

.PHONY:test

test:

        @echo $(SRC)

        @echo $(OBJ)

如何使用make命令形成多个可执行程序:

我们可以先定义一个依赖关系,它的依赖方法为空,它的依赖文件就是我们要生成的所有可执行程序,这样在推导时就会先去生成它的依赖文件,即我们需要的可执行程序,生成后因为它的依赖方法为空,make命令执行结束。如图:

  • makefile文件:

  • 效果:

二、进度条小程序

2.1、回车与换行

  • 回车概念:光标跳到当前行的起始位置。符号:\r。
  • 换行概念:光标相对于行起始位置的距离不变,跳转到下一行。符号:\n。

在C/C++语言中,对 \n 进行了处理,在语言上这一个符号即进行了回车,也进行了换行。

2.2、行缓冲区

示例代码一:

效果:先输入hello,Linux,再睡眠两秒。

示例代码二:

效果:先睡眠两秒,再输出hello,Linux。

是什么造成上面两段代码的差异的呢?首先,这两段代码的执行顺序都是一样的,都是先执行printf函数,再执行sleep函数。其次,我们要知道printf函数并不是直接将内容输出到显示器上,而是将内容输出到缓冲区,当缓冲区满了或者程序结束时会对缓冲区进行刷新,这里之所以会有差异是因为 \n 除了换行还会强制刷新缓冲区。

如何不通过\n强制刷新缓冲区:使用fflush函数。

2.3、练手-倒计时程序

  1 #include <stdio.h>2 #include <unistd.h>3 4 int main()5 {6     int count = 10;7     while(count >= 0)                                                                                                                                                           8     {9         printf("%-2d\r", count); // \r回车,但是没有换行,也就没有刷新10         fflush(stdout);11         count--;12         sleep(1);13     }14     printf("\r\n");15     return 0;16 }17 

解释:上面代码通过每次输出内容都带上 \r 来实现倒计时的数字在同一行,并且每次下一个数会在该行覆盖上一个数,不过需要注意的是,第一次输出的是10,占两位,后面输出的都是一位数字,因为每次还向显示器文件输出了回车,所以新的内容会在显示器文件起始处写入,这样每次都只能覆盖第一个数字,在显示器文件中0一直存在,导致我们看到的效果就是除10以外的其他数字后面也都跟着一个0。解决办法就是以%2d的格式向显示器文件进行写入,这样即使是一个数字也会占两位,这样就可以将0覆盖掉。但是因为C语言中默认这种格式是右对齐的,数字在右边,左侧会有空格,展现出来不好看,所以我们加一个负号,使其左对齐。

2.4、进度条程序

  • process.h:
#pragma once//version//void Process();
//void Process(double total, double current);
void FlushProcess(double total, double current);
  • process.c:
#include "process.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <string.h>#define NUM 101
#define STYLE '='
#define POINT '.'
#define SPACE ' '
const int pnum = 6;// version 2:真实的进度条,应该根据具体的比如下载的量,来动态刷新进度
void FlushProcess(double total, double current)
{// 1. 更新当前进度的百分比double rate = (current/total)*100;// printf("test: %.1lf%%\r", rate);// fflush(stdout);// 2. 更新进度条主体char bar[NUM]; // 我们认为,1% 更新一个等号memset(bar, '\0', sizeof(bar));for(int i = 0; i < (int)rate; i++){bar[i] = STYLE;}// 3. 更新旋转光标或者是其他风格static int num = 0;num++;num%=pnum;char points[pnum+1];memset(points, '\0', sizeof(points));for(int i = 0; i < pnum; i++){if(i < num) points[i] = POINT;else points[i] = SPACE;}// 4. test && printfprintf("[%-100s][%.1lf%%]%s\r", bar, rate, points);fflush(stdout);//sleep(1);
}// version 1
//void Process()
//{
//    const char *lable = "|/-\\";
//    int len = strlen(lable);
//    char bar[NUM];
//    memset(bar, '\0', sizeof(bar));
//    int cnt = 0;
//    while(cnt <= 100)
//    {
//        printf("[%-100s][%d%%][%c]\r", bar, cnt, lable[cnt%len]);
//        fflush(stdout);
//        bar[cnt] = STYLE;
//        cnt++;
//        usleep(100000);
//    }
//
//    printf("\r\n");
//}
  • main.c:
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include "process.h"typedef void (*flush_t)(double total, double current);// 这是一个刷新的函数指针类型const int base = 100;
double total = 2048.0; // 2048MB
double once = 0.1;     // 0.5MB// 进度条的调用方式
void download(flush_t f)
{double current = 0.0;while(current < total){// 模拟下载行为int r = rand() % base + 1; // [1, 10]double speed = r * once;current += speed;if(current >= total) current = total;usleep(10000);// 更新除了本次新的下载量// 根据真实的应用场景,进行动态刷新//Process(total, 1.0);f(total, current);//printf("test: %.1lf/%.1lf\r", current, total);//fflush(stdout);}printf("\n");
}int main()
{srand(time(NULL));download(FlushProcess);download(FlushProcess);download(FlushProcess);return 0;
}
  • makefile:
process:main.c process.cgcc -o $@ $^ -std=c99
.PHONY:clean
clean:rm -f process

效果:

三、版本控制器-Git

3.1、版本控制器

为了能够更⽅便我们管理这些不同版本的⽂件,便有了版本控制器。所谓的版本控制器,就是能让你 了解到⼀个⽂件的历史,以及它的发展过程的系统。通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统,同时也⽅便多⼈协同作业。

⽬前最主流的版本控制器就是Git。Git可以控制电脑上所有格式的⽂件,例如doc、excel、dwg、 dgn、rvt等等。对于我们开发⼈员来说,Git最重要的就是可以帮助我们管理软件开发项⽬中的源代码⽂件!

安装git:

yum install git            #centOS版本

3.2、gitee的使用

3.2.1、如何创建仓库

首先我们需要先注册一个gitee账号,然后登录。登录后点击右上角加号,点击新建仓库,如下图:

然后会进入如下界面:

这里仓库名称可以随意起,路径会自动生成,不用管,仓库介绍根据自己的实际情况写就可以。仓库可以开源也可以私有,根据情况选择。

建议对仓库进行初始化,希望仓库存储的是哪种语言的代码,就选择哪种语言就可以,.gitignore模版和语言选择一样的就行,开源许可证可以不选,对于模版的选择,如果这个仓库是自己用的选Readme就可以,后面两个多人协作会涉及,分支模型可以不选,不选默认单分支,如果需要多分支可以根据情况选择。然后点击创建就可以了。

3.2.2、如何将仓库克隆到本地

首先找到刚刚创建好的仓库,点击克隆/下载。如图:

点击后:

选择HTTPS,点击蓝框里的赋值按钮。然后回到Linux平台,输入命令:git clone + HTTPS链接。

然后该仓库就会被同步到本地了。

3.2.3、gitee三板斧

  • git add:

作用:将代码放到刚才下载好的⽬录中。

语法:git add [⽂件名]

  • git commit:

作用:提交改动到本地。

语法:git commit -m "XXX"

提交的时候应该注明提交⽇志,描述改动的详细内容。

  • git push:

作用:同步到远端服务器上。

语法:git push

需要填⼊用户名密码(gitee的)。同步成功后,刷新Gitee⻚⾯就能看到代码改动了。

配置免密提交:git本地免密码和账号pull、push-CSDN博客

注意:第一次提交会提示设置用户名和邮箱,邮箱要和注册gitee时的邮箱相同,否则看不到提交后的小绿点。

3.2.4、git pull

作用:将远端仓库同步到本地

语法:git pull

注意:当远端仓库和本地仓库不一致时,会导致无法提交,这时需要通过该指令使本地仓库和远端同步。

四、调试器-gdb/cgdb

4.1、预备

  • 程序的发布⽅式有两种, debug 模式和 release 模式, Linux gcc/g++ 出来的⼆进制程序,默认是 release 模式。
  • 要使⽤gdb调试,必须在源代码⽣成⼆进制程序的时候,加上 -g 选项,如果没有添加,程序⽆法被 编译。

$ gcc mycmd.c -o mycmd         # 默认模式,不⽀持调试

$ file mycmd

mycmd: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=82f5cbaada10a9987d9f325384861a88d278b160, for GNU/Linux3.2.0, not stripped

$ gcc mycmd.c -o mycmd  -g         # debug模式

$ file mycmd

mycmd: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3d5a2317809ef86c7827e9199cfefa622e3c187f, for GNU/Linux

3.2.0, with debug_info, not stripped

4.2、常见使用

开始:gdb binFile

退出:ctrl + d 或 quit 调试命令

命令作用样例
list/l显⽰源代码,从上次位置开始,每次列出10⾏list/l 10
list/l   函数名列出指定函数的源代码list/l  main
list/l ⽂件名:⾏号列出指定⽂件的源代码list/l mycmd.c:1
r/run从程序开始连续执⾏,遇到断点则停下,没有断点跑完程序run
n/next单步执⾏,不进⼊函数内部next
s/step单步执⾏,进⼊函数内部step
break/b  行号在指定行号设置断点b 10
break/b [⽂件名:]⾏号在指定文件的指定⾏号设置断点break 10 ;break test.c:10
break/b 函数名在函数开头设置断点break main
info break/b查看当前所有断点的信息info break/b
finish执⾏到当前函数返回,然后停⽌finish
print/p 表达式打印表达式的值print start+end
p 变量打印指定变量的值p x
set var 变量=值修改变量的值set var i=10
continue/c从当前位置开始连续执⾏程序continue
delete/d breakpoints删除所有断点delete breakpoints
delete/d breakpoints n删除序号为n的断点(breakpoints可不加)delete  (breakpoints) 1
disable breakpoints禁⽤所有断点disable breakpoints
enable breakpoints启⽤所有断点enable breakpoints
info/i breakpoints查看当前设置的断点列表info breakpoints
display 变量名跟踪显⽰指定变量的值(每次停⽌时)display x
undisplay 编号取消对指定编号的变量的跟踪显⽰undisplay 1
until X⾏号执⾏到指定⾏号until 20
backtrace/bt查看当前执⾏栈的各级函数调⽤及参数backtrace
info/i locals查看当前栈帧的局部变量值info locals
quit退出GDB调试器quit

注意:

  • gdb会记录最新的一条命令,按回车默认是执行该命令。如 list 1 后按回车,会从上次代码结束的位置继续显示。
  • 在一个调试周期内,断点的编号是递增的。例如我们设置了两个断点,它们的序号是1,2,然后我们删除它们在重新设置断点,这时断点的编号是从3开始的。
  • 禁用和启用断点的关键字(disable、enable)后可以直接加断点编号,表示禁用或启用某一个断点。

4.3、常见技巧

上⾯的基本调试还是麻烦,虽然是⿊屏,但是还是想看到代码调试,推荐安装cgdb:

Ubuntu: sudo apt-get  install  -y  cgdb

Centos:  sudo yum  install  -y  cgdb

4.3.1、watch

执⾏时监视⼀个表达式(如变量)的值。如果监视的表达式在程序运⾏期间的值发⽣变化,GDB会暂停程序的执⾏,并通知使⽤者。

(gdb) watch result

Hardware watchpoint 2: result

(gdb) c

Continuing.

Hardware watchpoint 2: result

Old value = 0

New value = 1

如果你有⼀些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你。

4.3.2、set var 确定问题原因

作用:更改某个变量值,帮助我们进一步锁定问题。

(gdb) set var flag=1         # 更改flag的值,确认是否是它的原因

有时我们调试bug时可能发现是某一个变量值的错误导致的问题,但我们无法确定判断是否准确,这时我们可以通过 set var 修改变量值,在重新通过 run 命令再次调试看结果来观察我们的判断是否准确。这样的好处是避免频繁退出调试去修改代码。

4.3.3、条件断点

  • 添加条件断点:

(gdb) b 9 if i == 30         # 9是⾏号,表⽰新增断点的位置

  • 给已经存在的断点新增条件:

(gdb) info b

Num                 Type                 Disp Enb Address                                 What

1                 breakpoint        keep y  0x00005555555551c3          in main at mycmd.c:20

                   breakpoint already hit 1 time

2                 breakpoint        keep y 0x0000555555555186           in Sum at mycmd.c:9

(gdb) condition 2 i==30         #给2号断点,新增条件i==30

注意:

  • 条件断点添加常⻅两种⽅式:1. 新增 2. 给已有断点追加。注意两者的语法有区别,不要写错了。
  • 新增:b ⾏号/⽂件名 : ⾏号/函数名  if  i  ==  30(条件)
  • 给已有断点追加:condition  2  i==30,其中2是已有断点编号,没有if。

相关文章:

Linux之基础开发工具二(makefile,git,gdb)

目录 一、自动化构建-make/makefile 1.1、背景 1.2、基本使用 1.3、推导过程 1.4、语法拓展 二、进度条小程序 2.1、回车与换行 2.2、行缓冲区 2.3、练手-倒计时程序 2.4、进度条程序 三、版本控制器-Git 3.1、版本控制器 3.2、gitee的使用 3.2.1、如何创建仓库 …...

cesium之自定义地图与地图叠加

在appvue中,cesium支持更换不同的地图资源,代码如下 <template><div id"cesiumContainer" ref"cesiumContainer"></div> </template><script setup> import * as Cesium from cesium; import "./Widgets/widgets.css&…...

链表结构深度解析:从单向无头到双向循环的实现全指南

上篇博客实现动态顺序表时&#xff0c;我们会发现它存在许多弊端&#xff0c;如&#xff1a; • 中间/头部的插⼊删除&#xff0c;时间复杂度为O(N) • 增容需要申请新空间&#xff0c;拷⻉数据&#xff0c;释放旧空间。会有不⼩的消耗。 • 增容⼀般是呈2倍的增⻓&#xff0c;…...

Apache Velocity代码生成简要介绍

Apache Velocity 概述 Apache Velocity 是一个基于 Java 的模板引擎&#xff0c;它允许将 Java 代码与 HTML、XML 或其他文本格式分离&#xff0c;实现视图与数据的解耦。在 Web 开发中&#xff0c;Velocity 常用于生成动态网页内容&#xff1b;在其他场景下&#xff0c;也可用…...

阿里云前端Nginx部署完,用ip地址访问却总访问不到,为什么?检查安全组是否设置u为Http(80)!

根据你的描述&#xff0c;Ping测试显示数据包无丢失但无法通过公网IP访问服务&#xff0c;说明网络基础层&#xff08;ICMP协议&#xff09;是通畅的&#xff0c;但更高层&#xff08;如TCP/UDP协议或服务配置&#xff09;存在问题。以下是系统性排查与解决方案&#xff1a; 一…...

【Hive入门】Hive行级安全:基于Apache Ranger的细粒度访问控制深度解析

引言 在大数据时代&#xff0c;数据安全与隐私保护已成为企业不可忽视的核心需求。传统表级权限控制已无法满足"同一张表不同用户看到不同数据"的业务场景&#xff0c;行级安全(Row-Level Security)成为数据仓库系统的必备能力。 1 行级安全概述 1.1 什么是行级安全…...

Marin说PCB之1000-BASE-T1的PCB设计总结--04

另外一路的1000-BASE-T1 Circuit&#xff1a;千兆以太网的仿真电路原理图的连接搭建方式如下&#xff1a; &#xff08;共模电感的连接需要特别注意一下PIN序别搞错了&#xff09; 这一路1000-BASE-T1 Circuit是做了兼容设计的&#xff1a; 其中电容C2099和C2100是百兆以太网的…...

两数之和(暴力+哈希查找)

目录 ​ 一.题目 二.解题过程 题目解析 方法一&#xff08;暴力求解&#xff09; 思路 代码 提交结果 方法二&#xff08;哈希查找&#xff09; 思路 代码 提交结果 作者的个人gitee​​ 作者的算法讲解主页▶️ 每日一言&#xff1a;“愿你纵踩淤泥&#xff0c;也要…...

Qt项目——天气预报

目录 前言结果预览工程文件窗体无状态栏窗口跟随移动HTTP基本概念JSON数据QT解析JSON数据结语 前言 通过对之前Qt的学习其实我们就已经有一点经验了&#xff0c;做天气预报只需要了解以下内容&#xff1a; stylesheet界面美化 Json数据解析 HTTP通信 自定义控件绘制温度 结果预…...

智能推理DeepSeek-R1+Word深度整合业级智能办公构建

前引&#xff1a; 当我们将DeepSeek-R1深度集成到Word时&#xff0c;实际上是在构建智能办公的"数字神经系统"。这个系统不仅理解文字内容&#xff0c;更能感知用户意图&#xff0c;在恰当的时刻提供精准的智能辅助。随着RAG&#xff08;检索增强生成&#xff09;技术…...

【C++ Qt】常用输入类下:Combo Box/Spin Box/DataTimeEdit/Dial/Slide

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论​&#xff1a; 在Qt开发框架中&#xff0c;UI组件是构建用户交互界面的基石。本章将详细探讨Qt中常用的UI组件&#xff0c;包括下拉框&#xff08;QComboBox&#xff…...

基于Piecewise Jerk Speed Optimizer的速度规划算法(附ROS C++/Python仿真)

目录 1 时空解耦运动规划2 PJSO速度规划原理2.1 优化变量2.2 代价函数2.3 约束条件2.4 二次规划形式 3 算法仿真3.1 ROS C仿真3.2 Python仿真 1 时空解耦运动规划 在自主移动系统的运动规划体系中&#xff0c;时空解耦的递进式架构因其高效性与工程可实现性被广泛采用。这一架…...

K8s 常用命令、对象名称缩写汇总

K8s 常用命令、对象名称缩写汇总 前言 在之前的文章中已经陆续介绍过 Kubernetes 的部分命令&#xff0c;本文将专题介绍 Kubernetes 的常用命令&#xff0c;处理日常工作基本够用了。 集群相关 1、查看集群信息 kubectl cluster-info # 输出信息Kubernetes master is run…...

C++编程语言:从高效系统开发到现代编程范式的演进之路

目录 前言一、c简介1.1 起源1.2 c的特点 二、开发环境搭建 2.1. 安装 Qt 开发工具2.2 修改编码环境 2.3创建第一个 Qt 项目2.4 c的编译过程2.5 代码示例 2.6 qt疑难杂症 2.6.1 遇到无法删除代码&#xff0c;一点击光标就变成小黑块2.6.2 遇到运行不弹出终端 ​编辑 2.6.3 遇到…...

OpenCV进阶操作:角点检测

文章目录 一、角点检测1、定义2、检测流程1&#xff09;输入图像2&#xff09;图像预处理3&#xff09;特征提取4&#xff09;角点检测5&#xff09;角点定位和标记6&#xff09;角点筛选或后处理&#xff08;可选&#xff09;7&#xff09;输出结果 二、Harris 角点检测&#…...

广州华锐视点邀您参与2025广交会VRAR展【5月10-12日】

2025 广交会数字显示与元宇宙生态博览会暨第 9 届世界 VR&AR 展将在广州盛大举行 。时间&#xff1a;2025 年 5 月 10 日至 12 日&#xff0c;广州华锐视点作为一家深耕 VR、AR、AI、元宇宙内容制作领域的企业&#xff0c;也将携旗下众多创新产品和解决方案闪耀登场&#x…...

mac m2 安装 hbase

默认安装好了 homebrew。 1. 终端先更新下 homebrew brew upgrade再安装 hbase brew install hbase 安装完会有如下图的内容 2. 按照提示启动 hbase brew services start hbase返回启动成功 3. 访问 http://localhost:16010 检验一下 启动成功 4. 在启动 hbase shell之…...

k8s node 报IPVS no destination available

在 Kubernetes 集群中&#xff0c;IPVS no destination available 错误通常表示 kube-proxy&#xff08;IPVS 模式&#xff09;无法为 Service 找到可用的后端 Pod。这会导致流量无法正确转发&#xff0c;影响服务可用性。以下是详细的排查和解决方法&#xff1a; 一、错误原因…...

MySQL 中 EXISTS (SELECT 1 FROM ...) 的用法详解

EXISTS (SELECT 1 FROM ...) 是 MySQL 中用于存在性检查的核心语法&#xff0c;其核心逻辑是判断子查询是否返回至少一行数据。以下从作用原理、使用场景、性能优化等方面展开解析&#xff0c;并结合具体示例说明。 1. 基本语法与作用原理 语法结构&#xff1a; SELECT 列名 F…...

荣耀A8互动娱乐组件部署实录(第3部分:控制端结构与房间通信协议)

作者&#xff1a;曾在 WebSocket 超时里泡了七天七夜的苦命人 一、控制端总体架构概述 荣耀A8控制端主要承担的是“运营支点”功能&#xff0c;也就是开发与运营之间的桥梁。它既不直接参与玩家行为&#xff0c;又控制着玩家的行为逻辑和游戏规则触发机制。控制端的主要职责包…...

前端-HTML+CSS+JavaScript+Vue+Ajax概述

HTML&#xff08;超文本标记语言&#xff09;常见标签 <html><head> <title>这是标题的内容&#xff0c;显示在浏览器的头部</title></head><body><!-- 这里面的内容在浏览器显示给用户看 --><!-- h1 -> h6 : 标题从大到小 …...

20250506格式化NanoPi NEO开发板使用Ubuntu core16.04系统的TF启动卡

https://www.sdcard.org/downloads/formatter/eula_windows/SDCardFormatterv5_WinEN.zip 20250506使用SDCardFormatter工具格式化NanoPi NEO开发板使用Ubuntu core16.04系统的TF启动卡 2025/5/6 20:04 缘起&#xff1a;使用友善之臂的NanoPi NEO开发板&#xff0c;制作了Ubunt…...

信息时代的政治重构:网络空间与主权的未来

一、网络空间&#xff1a;暴力垄断的终结 无边界主权的崛起 网络空间作为“第五阶段”的暴力竞争场域&#xff0c;打破传统领土垄断。政府无法像控制物理世界那样垄断网络暴力&#xff0c;类似公海的法律真空状态。 边区类比&#xff1a;中世纪的安道尔&#xff08;法西共管避…...

Kotlin重构Android项目实践

以下是使用 Kotlin 重构 Android 项目的 5 个常见场景实践&#xff0c;通过对比 Java 实现方式&#xff0c;展示 Kotlin 的简洁性和现代特性&#xff1a; 场景 1&#xff1a;数据类替代 Java POJO Java 传统实现&#xff1a; public class User {private String name;private…...

Vue + Element UI 表单弹窗输入法卡顿问题解决方案

Vue Element UI 表单弹窗输入法卡顿问题解决方案 前言 在使用 Vue 和 Element UI 开发后台管理系统时&#xff0c;经常会遇到 el-dialog 弹出表单对话框的场景。然而&#xff0c;很多开发者可能会遇到一个棘手的问题&#xff1a;当调用 resetFields() 方法重置表单时&#x…...

ubantu安装CUDA

想要通过llama.cpp的方式跑deepseek R1模型。在按照https://huggingface.co/unsloth/DeepSeek-R1-GGUF教程去配环境时报错了。具体如下&#xff1a; (base) oemcore:~/Desktop/deepseek_llama.cpp$ sudo cmake llama.cpp -B llama.cpp/build -DBUILD_SHARED_LIBSOFF -DGGM…...

Python生活手册-Numpy多维数组构建:从快递分拣到智能家居的数据变形术

一、快递分拣系统&#xff08;基础构建&#xff09; 1. 电子面单生成&#xff08;列表转数组&#xff09; import numpy as np手工录入的快递单号 纸质单号 [["SF123", "JD456", "EMS789"],["YT012", "ZT345", "YZ6…...

数据库的范围查询

范围查询 B树迭代器 迭代器接口 B树的基本操作包括用于范围查询的查找和迭代。B树的位置由状态化的迭代器 BIter 表示。 // 查找小于或等于输入键的最近位置 func (tree *BTree) SeekLE(key []byte) *BIter// 获取当前键值对 func (iter *BIter) Deref() ([]byte, []byte)/…...

JS DAY4 日期对象与节点

一日期对象 日期对象:用来表示时间的对象 作用:可以得到当前系统时间 1.实例化 在代码中发现了 new 关键字时&#xff0c;一般将这个操作称为实例化 创建一个时间对象并获取时间 时间必须实例化 获得当前时间 const date new Date() 获得指定时间 const date new Date(…...

【Leetcode 每日一题 - 补卡】1007. 行相等的最少多米诺旋转

问题背景 在一排多米诺骨牌中&#xff0c; t o p s [ i ] tops[i] tops[i] 和 b o t t o m s [ i ] bottoms[i] bottoms[i] 分别代表第 i i i 个多米诺骨牌的上半部分和下半部分。&#xff08;一个多米诺是两个从 1 1 1 到 6 6 6 的数字同列平铺形成的 —— 该平铺的每一半…...

Android设备运行yolov8

放假这几天搞了一个基于uniapprk3588实现了一版yolo检测 这个是基于前端调用后端api来实现&#xff0c;感觉还可以&#xff0c;但是需要有网络才能进行图像检测&#xff0c;网络不稳定就会出现等待时间会比较久的问题&#xff0c;然后有做了一个在做了一个Android版本的图像检…...

Debezium MySqlValueConverters详解

Debezium MySqlValueConverters详解 1. 类的作用与功能 1.1 核心作用 MySqlValueConverters是Debezium中负责MySQL数据类型转换的核心类,主要功能包括: 数据类型映射:将MySQL的数据类型映射到Kafka Connect的Schema类型值转换:将MySQL的原始值转换为Kafka Connect可用的…...

Redis从入门到实战——实战篇(下)

四、达人探店 1. 发布探店笔记 探店笔记类似于点评网站的评价&#xff0c;往往是图文结合。对应的表有两个&#xff1a; tb_blog&#xff1a;探店笔记表&#xff0c;包含笔记中的标题、文字、图片等tb_blog_comments&#xff1a;其他用户对探店笔记的评价 步骤①&#xff1…...

算法中的数学:质数(素数)

1.质数 1.1定义 一个大于1的自然数&#xff0c;除了1和它自身外&#xff0c;不能被其他自然数整除&#xff0c;那么他就是质数&#xff0c;否则他就是合数。 注意&#xff1a;1既不是质数也不是合数 唯一的偶质数是2&#xff0c;其余所有质数都是奇质数 1.2质数判定求法 试除法…...

linux、window安装部署nacos

本文以nacos 2.2.0为例 文章目录 1.下载安装包2.按需修改配置配置单机模式配置内存 -Xms -Xmx -Xmn配置数据库为MySQL 3. 访问http://ip:8848/nacos4.常见问题找不到javac命令 1.下载安装包 打开官网&#xff0c;下载2.2.0版本 2.按需修改配置 配置单机模式 默认集群模式&…...

C++ 外观模式详解

外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它为复杂的子系统提供一个简化的接口。 概念解析 外观模式的核心思想是&#xff1a; 简化接口&#xff1a;为复杂的子系统提供一个更简单、更统一的接口 降低耦合&#xff1a;减少客户端与子…...

42. 接雨水(相向双指针/前后缀分解),一篇文章讲透彻

给定一个数组&#xff0c;代表柱子的高度 求出下雨之后&#xff0c;能接的水有多少单位。我们将每一个柱子想象成一个水桶&#xff0c;看他能接多少水 以这个水桶为例&#xff0c;他所能接的水取决于左边的柱子的最大高度和右边柱子的最大高度&#xff0c;因为只有柱子高的时候…...

vue实现AI问答Markdown打字机效果

上线效果 功能清单 AI问答&#xff0c;文字输出跟随打字机效果格式化回答内容&#xff08;markdown格式&#xff09;停止回答&#xff0c;复制回答内容回答时自动向下滚动全屏切换历史问答查看 主要技术 vue 2.7.1markdown-it 14.1.0microsoft/fetch-event-source 2.0.1high…...

【QT】QT中的事件

QT中的事件 1.事件的定义和作用2.QT中事件产生和派发流程2.1 步骤2.2 图示示例代码&#xff1a;&#xff08;event函数接收所有事件&#xff09; 3.常见的事件3.1 鼠标事件示例代码&#xff1a;现象&#xff1a; 3.2 按键事件3.3 窗口大小改变事件 4.举例说明示例代码&#xff…...

【QT】QT中的软键盘设计

QT的软键盘设计 1.软键盘制作步骤2.介绍有关函数的使用3.出现的编译错误及解决办法示例代码1&#xff1a;按键事件实现软键盘现象&#xff1a;示例代码2&#xff1a;按键事件实现软键盘&#xff08;加特殊按键&#xff09;现象&#xff1a; 软键盘移植到新的工程的步骤&#xf…...

【Unity】一个AssetBundle热更新的使用小例子

1.新建两个预制体&#xff1a; Cube1&#xff1a;GameObject Material1&#xff1a;Material Cube1使用了Material1材质 之后设置打包配置 Cube1的打包配置为custom.ab Material1的打包配置为mat.ab 2.在Asset文件夹下创建Editor文件夹&#xff0c;并在Editor下创建BuildBundle…...

【Bootstrap V4系列】学习入门教程之 组件-按钮组(Button group)

Bootstrap V4系列 学习入门教程之 组件-按钮组&#xff08;Button group&#xff09; 按钮组&#xff08;Button group&#xff09;一、Basic example二、Button toolbar 按钮工具条三、Sizing 尺寸四、Nesting 嵌套五、Vertical variation 垂直变化 按钮组&#xff08;Button …...

Linux进程间的通信

IPC 即 Inter-Process Communication&#xff0c;也就是进程间通信&#xff0c;它指的是在不同进程之间进行数据交换和协调同步的机制。在操作系统里&#xff0c;每个进程都有自己独立的内存空间&#xff0c;一般情况下不能直接访问其他进程的内存&#xff0c;所以需要借助 IPC…...

常用非对称加密算法的Python实现及详解

非对称加密算法&#xff08;Asymmetric Encryption&#xff09;使用公钥加密、私钥解密&#xff0c;解决了对称加密的密钥分发问题。本文将详细介绍 RSA、ECC、ElGamal、DSA、ECDSA、Ed25519 等非对称加密算法的原理&#xff0c;并提供Python实现代码及安全性分析。 1. 非对称加…...

【题解-洛谷】B4303 [蓝桥杯青少年组省赛 2024] 字母移位

题目&#xff1a;B4303 [蓝桥杯青少年组省赛 2024] 字母移位 题目描述 字母移位表示将字母按照字母表的顺序进行移动。 例如&#xff0c; b \texttt{b} b 向右移动一位是 c \texttt{c} c&#xff0c; f \texttt{f} f 向左移动两位是 d \texttt{d} d。 特别地&#xff0c;…...

详讲viewer查看器

将Python与Cesium结合起来&#xff0c;可以实现高效的数据处理与可视化展示。本文将详细介绍如何在Python环境中集成Cesium&#xff0c;以及实现数据可视化的具体方法。 我们可以通过在app.vue中的修改来更改我们查看器的显示方法 修改前 修改后 还可以进行各式各样的自定义操作…...

开关电源原理

开关电源原理 一、 开关电源的电路组成&#xff1a; 开关电源的主要电路是由输入电磁干扰滤波器&#xff08;EMI&#xff09;、整流滤波电路、功率变换电路、PWM控制器电路、输出整流滤波电路组成。辅助电路有输入过欠压保护电路、输出过欠压保护电路、输出过流保护电路、输出短…...

数据库的并发控制

并发控制 12.1 并发级别 问题&#xff1a;交错的读写 并发客户端可以随意进入和退出事务&#xff0c;并在中途请求读取和写入。为了简化分析&#xff0c;假设enter/exit/read/write是原子步骤&#xff0c;因此并发事务只是这些步骤的交错。 我们还将区分只读事务和读写事务…...

力扣第448场周赛

赛时成绩如下: 这应该是我力扣周赛的最好成绩了(虽然还是三题) 1. 两个数字的最大乘积 给定一个正整数 n。 返回 任意两位数字 相乘所得的 最大 乘积。 注意&#xff1a;如果某个数字在 n 中出现多次&#xff0c;你可以多次使用该数字。 示例 1&#xff1a; 输入&#xff1…...

关于Python:9. 深入理解Python运行机制

一、Python内存管理&#xff08;引用计数、垃圾回收&#xff09; Python&#xff08;CPython&#xff09;采用的是&#xff1a; “引用计数为主&#xff0c;垃圾回收为辅” 的内存管理机制。 也就是说&#xff1a; 引用计数机制&#xff1a;负责大部分内存释放&#xff0c;简…...