C语言之编译和debug工具

gcc

gcc是GUN项目为C和C++提供的编译器

入门案例

gcc编译器最简单的使用案例:gcc hello.c -o hello,hello.c是源文件,-o参数指定了结果文件的名称

gcc命令的选项:

  • -v:打印编译细节
  • -E:仅仅进行预处理,把预处理结果输出到控制台
  • -S:编译源文件
  • -c:编译并汇编源文件
  • -o:指定输出文件
  • -I <dir>:指定某个文件夹作为搜索路径
  • -L:为gcc增加一个搜索链接库的目录

工作机制

一般高级语言的编译过程,可以分为预处理、编译、汇编、链接四个阶段。

预处理

预处理是编译过程中的第一步,处理各种预处理命令,包括头文件的包含(#include)、宏定义的扩展(#define)、条件编译的选择(#if #endif)等

打印出预处理的结果:gcc -E hello.c

源代码:hello.c

#include <stdio.h>#define HELLO_LINUX "hello Linux!\n"
#define HELLO_MAC "hello MAC!\n"
#define HELLO_WINDOWS "hello Windows!\n"int main(int argc, char const *argv[]) {#if defined(__linux__)printf(HELLO_LINUX);#elif defined(__APPLE__) || defined(__MACH__)printf(HELLO_MAC)#elif defined(__WIN32__)printf(HELLO_WINDOWS);#endifint a = 1;int b = 2;#if a > bprintf("111\n");#elseprintf("222\n");#endifreturn 0;
}

打印出的结果:

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<命令行>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<命令行>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 375 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 392 "/usr/include/sys/cdefs.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 393 "/usr/include/sys/cdefs.h" 2 3 4
# 376 "/usr/include/features.h" 2 3 4
# 399 "/usr/include/features.h" 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 10 "/usr/include/gnu/stubs.h" 3 4
# 1 "/usr/include/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/gnu/stubs.h" 2 3 4
# 400 "/usr/include/features.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4# 1 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 1 3 4
# 212 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 3 4
typedef long unsigned int size_t;
# 34 "/usr/include/stdio.h" 2 3 4# 1 "/usr/include/bits/types.h" 1 3 4
# 27 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 28 "/usr/include/bits/types.h" 2 3 4typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
typedef unsigned long int __u_long;// 省略代码int main(int argc, char const *argv[]) {printf("hello Linux!\n");int a = 1;int b = 2;printf("222\n");return 0;
}

从预处理的结果中观察预处理究竟做了什么:

  • 文件包含:#include 头文件:会把头文件整个复制到当前源码文件中
  • 宏展开:#define 宏名 常量:预处理会进行宏替换,把宏名提换为它所代表的常量
  • 条件编译:#if #endif:判断应该保留哪个分支,裁剪到多余的分支

编译

编译:编译器进行词法分析、语法分析,把源代码翻译成汇编语言。

打印出gcc编译器生成的汇编语言:gcc -S hello.c,会在当前目录下生成hello.s文件

生成的结果:

        .file   "hello.c".section        .rodata
.LC0:.string "hello Linux!"
.LC1:.string "222".text.globl  main.type   main, @function
main:
.LFB0:.cfi_startprocpushq   %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq    %rsp, %rbp.cfi_def_cfa_register 6subq    $32, %rspmovl    %edi, -20(%rbp)movq    %rsi, -32(%rbp)movl    $.LC0, %edicall    putsmovl    $1, -4(%rbp)movl    $2, -8(%rbp)movl    $.LC1, %edicall    putsmovl    $0, %eaxleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE0:.size   main, .-main.ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)".section        .note.GNU-stack,"",@progbits

汇编

汇编:把汇编代码翻译成机器代码,即目标代码

查看生成的机器代码:

  • 第一种方式:gcc - c hello.s,自动生成hello.o文件
  • 第二种方式:as -o hello.o hello.s,-o参数指定生成的目标文件

查看生成的目标文件的文件类型:file hello.o,结果:

hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
ELF文件

链接

链接:将符号引用和符号定义替换为可执行文件的虚拟内存地址

总结

编译过程分为四步:预处理、编译、汇编、链接

  • 预处理:处理预处理命令,包括文件包含、宏定义、条件编译

    • 查看预处理的结果:gcc -E 源码文件,会把预处理的结果打印到屏幕上
  • 编译:把预处理的结果编译为汇编文件

    • 查看编译的结果:gcc -S 源文件,会在当前目录下生成.s文件,.s文件中存储了汇编代码
  • 汇编:把汇编代码编译为机器代码

    • 查看汇编结果:gcc -c 汇编代码,会在当前目录下自动生成.o文件,.o文件中存储了机器代码
  • 链接:将机器代码中的符号引用和符号定义替换为可执行文件的虚拟内存地址,最终生成可执行文件

Makefile

简介

Makefile:一个文本文件,并且文件名就叫"Makefile"。它包含了一系列指令,定义了整个项目的编译规则。

优点:自动化编译,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率

make命令:解释Makefile文件的命令

make命令的工作原则:

  • 一个目标文件,只有在它依赖的目标文件被更改后,它才会被重新编译。如果依赖文件的修改时间比目标文件的创建时间晚,证明依赖文件在目标文件创建后又进行了修改
  • make工具会遍历所有的依赖文件,并且把它们对应的目标文件进行更新。编译的命令和这些目标文件及它们对应的依赖文件的关系则全部储存在 Makefile 中。

入门案例

案例1

不使用Makefile的情况下对一个项目进行编译,在这里使用到了静态链接库和动态链接库

项目的源代码:

main.c:主程序的入口

#include <stdio.h>
#include "add_minus.h"
#include "multi_div.h"int main(int argc, char const *argv[]) {printf("hello Cacu\n");int rst = 0;rst = add(3, 2);printf("3 + 2 = %d\n",rst);rst = minus(3, 2);printf("3 - 2 = %d\n",rst);rst = multi(3, 2);printf("3 * 2 = %d\n",rst);rst = div(3, 2);printf("3 / 2 = %d\n",rst);return 0;
}

add_minus.h:声明了加法和减法的接口

int add(int, int);
int minus(int, int);

multi_div.h:声明了乘法和除法的接口

int multi(int, int);
int div(int, int);

add_minus.c:实现了加法和减法的功能

#include "add_minus.h"int add(int x, int y) {return x + y;
}int minus(int x, int y) {return x - y;
}

multi_div.h:实现了乘法和除法的功能

#include "multi_div.h"int multi(int x, int y) {return x * y;
}int div(int x, int y) {return x / y;
}

从源代码到可执行文件的过程:

  • 编译源文件,生成目标文件:在这里分别编译3个".c"文件,生成".o"文件,".o"文件是目标文件,目标文件是二进制文件
    • gcc -c add_minus.c
    • gcc -c multi_div.c
    • gcc -c main.c
  • 链接目标文件,生成可执行文件:gcc -o main main.o add_minus.o multi_div.o,选项"-o"指定了目标文件的名称,这一步会把三个".o"文件链接为一个可执行文件
  • 清理:清理掉所有的目标文件:rm *.o

上面的案例演示了将源代码编译为可执行文件的基本流程,接下来还是以上面的源代码,演示静态链接库和动态链接库

  • 将每个.c文件都编译为目标文件:gcc -c main.c; gcc -c add_minus.c; gcc -c multi_div.c
  • 将add_minus.c编译为静态链接库:ar -r libadd_minus.a add_minus.o,ar命令用于生成静态链接库,-r 选项指定静态链接库的位置和名称,最好使用".o"文件来生成静态链接库,这样和平台是相关的。
  • 将multi_div.c编译为动态链接库:gcc multi_div.c -shared -o libmulti_div.so,-shared表示生成动态链接库,-o用于指定输出文件
  • 生成目标文件,同时连接静态库和动态库:gcc -o main main.o -L . -l multi_div -l add_minus,-L. 表示在当前目录下寻找库,-l指定库的名称,声明前缀lib和后缀.a、.so需要省略

案例2

最简单的Makefile文件,还是以案例1的代码作为源代码

main: main.c add_minus.c multi_div.cgcc -o main main.c add_minus.c multi_div.c

在控制台执行make命令,就会生成可执行文件main

语法

基本语法

Makefile文件的基本格式:

目标: 依赖命令   # 注意命令前必须是一个TAB键

make命令解析Makefile的工作机制:

  • 检测目标的依赖是否存在:生成目标前,会检查目标的依赖文件是否存在,如果不存在,会向下检索,检测是否有生成依赖的规则,如果没有,则报错
  • 检测目标是否需要更新:如果目标的依赖有一个被更新, 则目标会被更新

在上面的入门案例2中,可执行文件依赖所有的源文件,如果一个源文件被修改,那么所有的源文件都需要被重新编译,接下来对案例2进行优化:

main: main.o add_minus.o multi_div.ogcc -o main main.o add_minus.o multi_div.omain.o: main.cgcc -c main.cadd_minus.o: add_minus.cgcc -c add_minus.cmulti_div.o: multi_div.cgcc -c multi_div.c

在当前Makefile文件中,每个源文件都是独立的,修改一个源文件,其它源文件不需要一同编译。

变量和模式

Makefile中支持定义变量,使用 “变量=值” 的形式来定义变量,使用 “${变量}” 的形式来引用变量

变量的类型:普通变量、自带变量、自动变量

普通变量:变量=值,定义完直接使用即可

自带变量:Makefile提供的内置变量,变量名大写

  • CC:编译器名称,例如:CC=gcc
  • CPPFLAGS: 预处理的选项
  • CFLAGS:编译器的选项
  • LDFLAGS:链接器的选项

自动变量:只能在命令中使用,Makefile根据上下文自动赋值的变量。

在学习自动变量的含义前,首先回顾一下Makefile的基本规则:

目标: 依赖命令   # 注意命令前必须是一个TAB键

自动变量是对于上述格式的简化:

  • $@: 表示目标
  • $<: 表示第一个依赖
  • $^: 表示所有依赖, 组成一个列表, 以空格隔开, 如果这个列表中有重复的项则消除重复项。

模式:%,表示一个或多个字符,目标和依赖必须同时使用 %,表示它们有相同的名称。比如: main.o:main.c,可以写为 %.o: %.c

使用变量和模式来优化入门案例:

target=main
object=main.o add_minus.o multi_div.oCC=gcc
CPPFLAGS=-I ./${target}:${object}${CC} -o $@ $^%.o: %.c${CC} -o $@ -c $^ ${CPPFLAGS}

函数

makefile中的函数有很多,在这里学习两个最常用的。

wildcard:查找指定目录下的指定类型的文件

  • 案例:src=$(wildcard *.c),找到当前目录下所有后缀为.c的文件,赋值给src,等价于src=main.c fun1.c fun2.c

patsubst:匹配替换

  • 案例:obj=$(patsubst %.c, %.o, $(src)),把src变量里所有后缀为.c的文件替换成.o,等价于obj=main.o fun1.o fun2.o

使用函数来优化入门案例:

target=mainsrc=${wildcard ./*.c}
object=${patsubst %.c, %.o, ${src}CC=gcc
CPPFLAGS=-I ./${target}:${object}${CC} -o $@ $^%.o: %.c${CC} -o $@ -c $^ ${CPPFLAGS}

makefile清理操作

清理编译过程中产生的中间文件,make会把makefile里出现的第一个target当作缺省target。其他的除非是生成缺省target需要,不会执行。

Makefile中的clean命令通常不会被执行,需要用户手动执行make clean命令,来删除编译过程中产生的 “.o” 文件

clean命令的案例:

cleanrm -f *.o

实战案例

案例1:

target=abooksrc=${wildcard ./*.c}                # 查找当前目录下所有的.c文件
object=${patsubst %.c, %.o, ${src}}  # 将.c替换为.oCC=gcc
CPPFLAGS= -Wall -Wextra -pedantic -std=c99   # 指定编译时的参数${target}:${object}                 # $@ 目标  $^  全部参数${CC} -o $@ $^%.o: %.c${CC} -o $@ -c $^ ${CPPFLAGS}clean:                # 需要执行 make clean命令,如果删掉.o文件,make命令会重新执行rm -f *.o

在命令行执行make && make clean命令

GDB

GDB:GNU Debugger,Linux下的调试工具,可以调试C、Java、PHP等语言。

初步使用:

  • 在命令行输入gdb,即可进入gdb提供的交互式界面
  • 在交互式界面输入help,即可查看gdb提供的帮助文档

入门案例

程序的源代码:gdb3.c

#include <stdio.h>int main(int argc, char const *argv[]) {int a = 0;printf("请输入一个数字:");scanf("%d", &a);printf("%d的平方:%d\n", a, a * a);return 0;
}

编译:gcc -g gdb3.c -o gdb3,使用gdb调试程序,在编译时,必须要加上-g参数。

调试:

  • 进入gdb的交互式界面:gdb
  • 加载程序:file 可执行文件
  • 设置断点:break gdb3.c:4
  • 查看源代码:list
  • 运行程序:run,遇到断点后会自动停下
  • 单步执行:step,遇到用户的自定义函数,会进入自定义函数。在这里,单步执行时,如果程序卡住,表示用户需要在控制台输入数据
  • 查看变量:print 变量
  • 继续向下执行:continue,遇到断点会停下

被调试的程序编译时必须加入-g参数

使用gdb调试的C程序,在编译时,必须加上 -g 参数,加上调试信息,-g选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件。

判断文件是否带有调试信息:`readelf -S 可执行程序 | grep debug

交互式界面下的基本命令

运行程序:

  • run(简写r): 运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步命令
  • start:启动程序并立即停止在程序的入口处
  • continue(简写c) : 继续执行,到下一个断点停止(或运行结束)
  • next(简写n) : 单步跟踪程序,当遇到函数调用时,也不进入此函数体;此命令同step的主要区别是,step遇到用户自定义的函数,将步进到函数中去运行,而next则直接调用函数,不会进入到函数体内。
  • step (简写s):单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的
  • until(简写u):可以运行程序直到退出循环体
  • until+行号: 运行至某行,不仅仅用来跳出循环
  • finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。
  • call 函数(参数):调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)
  • quit(简写q) : 退出gdb

设置断点:

  • break 文件名:n (简写b n):在指定文件的第n行处设置断点
  • b fn1 if a>b:条件断点设置
  • break func(break缩写为b):在函数func()的入口处设置断点,如:break cb_button
  • delete 断点号n:删除第n个断点
  • disable 断点号n:暂停第n个断点
  • enable 断点号n:开启第n个断点
  • clear 行号n:清除第n行的断点
  • info b (info breakpoints) :显示当前程序的断点设置情况
  • delete breakpoints:清除所有断点:

查看源代码:

  • list :简记为 l ,其作用就是列出程序的源代码,默认每次显示10行。
  • list 行号:将显示当前文件以“行号”为中心的前后10行代码,如:list 12
  • list 函数名:将显示“函数名”所在函数的源代码,如:list main
  • list :不带参数,将接着上一次 list 命令的,输出下边的内容。

打印表达式

  • print 表达式(简记p): 其中“表达式”可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,那么“表达式”可以是任何C语言的有效表达式,包括数字,变量甚至是函数调用。
    • print a:将显示整数 a 的值
    • print ++a:将把 a 中的值加1,并显示出来
    • print name:将显示字符串 name 的值
    • print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数
    • print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数
  • display 表达式:在单步运行时将非常有用,使用display命令设置一个表达式后,它将在每次单步进行指令后,紧接着输出被设置的表达式及值。如: display a
  • watch 表达式:设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如: watch a
  • whatis :查询变量或函数
  • info function: 查询函数
  • info locals: 显示当前堆栈页的所有变量

查询运行信息

  • where/bt :当前运行的堆栈列表
  • bt backtrace 显示当前调用堆栈
  • up/down 改变堆栈显示的深度
  • set args 参数:指定运行时的参数
  • show args:查看设置好的参数
  • info program: 来查看程序的是否在运行,进程号,被暂停的原因。

使用经验

在上面的章节中,学习了gdb的基本知识,在这里,结合平时对于gdb的使用,总结一些常用的操作

查看函数调用栈中的栈帧

  • breaktrace命令,简写为bt
  • frame命令:简写为f,参数是一个数字,代表当前函数调用栈中第几个栈帧,栈帧由下到上从1开始编码。f 1,查看当前函数调用栈内main函数的情况
  • where命令:查看当前函数调用栈

当前函数内局部变量的值

info locals

让程序一直运行到从当前函数返回为止

finish命令

修改变量的值

set var 变量 = 值

监控某个变量的值

  • display命令:监控某个变量的值,程序每运行一行,自动显示该变量的值
  • undisplay命令:取消监控

启动程序时向程序中传递参数

第一种方式:在命令行中直接传递参数:可以在GDB命令行中使用run命令后面跟上程序的参数

gdb ./my_program
(gdb) run arg1 arg2

第二种方式:使用set args命令设置参数

gdb ./my_program
(gdb) set args arg1 arg2
(gdb) run

调试时指定跳到第几行

jump 行号,需要先在该行设置断点

debug模式下无法获取用户输入

在使用gdb进行调试时,gdb默认是运行在交互模式(interactive mode)下的,而交互模式会导致gdb无法正确地获取用户的输入。这是因为gdb会将标准输入重定向到自己的输入流,而不是终端。

解决这个问题的一种方法是将gdb设置为非交互模式(non-interactive mode),这样gdb就能够正确地获取用户的输入。可以在调试程序之前,在gdb中使用以下命令来设置非交互模式:

set pagination off
set non-stop on

这样设置后,gdb会禁用分页输出(pagination)和停止在非关键点(non-stop mode),从而允许程序在调试过程中正常运行,而不会暂停等待输入。

容易混淆的知识点

start和run的区别

start和run是两个用于启动程序的命令,它们有一些区别和不同的使用场景

  • start命令:start命令用于启动程序并立即停止在程序的入口处,然后等待调试器的进一步指令。它可以让你在程序刚刚开始执行时暂停,以便设置断点或进行其他调试操作。在使用start命令后,你可以使用continue命令继续程序的执行,或者使用其他GDB调试命令进行进一步的调试操作。
  • run命令:run命令用于启动程序并从程序的起始位置开始连续执行。它会一直执行程序,直到遇到断点、程序结束或其他调试终止条件。如果你不需要在程序刚开始执行时暂停,而是希望直接开始连续执行程序,则可以使用run命令。

常用操作

在程序执行过程中监视某个变量的改变

watch命令

执行完当前方法后返回到上一个方法

finish命令

程序中有fork函数,想要debug子进程,该怎么办?

在程序开始执行之前,输入命令 set follow-fork-mode child,表示fork后将进入子进程调试,子进程调试完成,输入命令 detach 脱离子进程,然后,set follow-fork-mode parent,设置模式为调试父进程。

调试指定线程

info threads:列出当前程序中的线程信息
thread <thread_number>:切换到指定线程

valgrind

用于检测内存泄漏的工具

安装:yum install -y valgrind

使用:valgrind --leak-check=full --show-leak-kinds=all -s <程序>,通过valgrind来执行程序,执行完成后,会显示程序中出现的内存错误。-s参数用于打印出检测到的错误

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

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

相关文章

Altshuller矛盾矩阵查询:基于python和streamlit

基于python和streamlit实现的Altshuller矛盾矩阵查询 import streamlit as st import json# 加载数据 st.cache_resource def load_data():with open(parameter.json, encodingutf-8) as f:parameters json.load(f)with open(way.json, encodingutf-8) as f:contradictions …

Maven的下载配置及在Idea中的配置

编写项目管理中存在的问题 在大型Java项目开发中&#xff0c;依赖管理是一个极其复杂的挑战。传统方式下&#xff0c;开发者需要手动下载并引入数十甚至上百个JAR包到项目中&#xff0c;这一过程不仅繁琐低效&#xff0c;还存在诸多痛点&#xff1a; 依赖传递性问题&#xff1a…

来聊聊C++中的vector

一.vector简介 vector是什么 C 中的 vector 是一种序列容器&#xff0c;它允许你在运行时动态地插入和删除元素。 vector 是基于数组的数据结构&#xff0c;但它可以自动管理内存&#xff0c;这意味着你不需要手动分配和释放内存。 与 C 数组相比&#xff0c;vector 具有更多的…

WVP-GB28181摄像头管理平台存在弱口令

免责声明&#xff1a;本号提供的网络安全信息仅供参考&#xff0c;不构成专业建议。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权&#xff0c;请及时与我联系&#xff0c;我将尽快处理并删除相关内容。 漏洞描述 攻击者可利用漏洞获取当前系统管…

讯飞语音听写(流式版)开发指南

语音交互大模型的功能越来越受到重视。讯飞语音听写&#xff08;流式版&#xff09;为开发者提供了一种高效、准确的语音识别解决方案。本文将基于 Home.vue、iat_xfyun.js 和 sparkChat.js 这三个文档&#xff0c;详细阐述讯飞语音听写&#xff08;流式版&#xff09;的开发逻…

基于kotlin native的C与kotlin互相调用

本文测试环境为ubuntu&#xff0c;没有使用IDE&#xff1b;从基本层面了解kotlin native环境中&#xff0c;C和kotlin的编译&#xff0c;互相调用。 1. kotlin 动态库 1.1 动态库编译 源码文件libktest.kt&#xff1a; //file name:libktest.kt OptIn(kotlin.experimental.…

【教学类-102-02】自制剪纸图案(留白边、沿线剪)02——Python+PS自动化添加虚线边框

背景需求: 01版本实现了对透明背景png图案边界线的扩展,黑线实线描边 【教学类-102-01】自制剪纸图案(留白边、沿线剪)01-CSDN博客文章浏览阅读974次,点赞15次,收藏7次。【教学类-102-01】自制剪纸图案(留白边、沿线剪)01https://blog.csdn.net/reasonsummer/article…

Python-函数参数

1. 参数基础 函数参数是向函数传递数据的主要方式&#xff0c;Python 提供了多种参数传递机制。 基本用法 def greet(name): # name 是形式参数print(f"Hello, {name}!")greet("Alice") # "Alice" 是实际参数使用场景&#xff1a;当函数需要…

《在 Ubuntu 22.04 上安装 CUDA 11.8 和 Anaconda,并配置环境变量》

安装 CUDA 11.8 和 Anaconda 并配置环境变量 在本教程中&#xff0c;我们将介绍如何在 Ubuntu 22.04 上安装 CUDA 11.8 和 Anaconda&#xff0c;并配置相应的环境变量。我们还将配置使用 阿里云镜像源 来加速软件包更新。以下是具体步骤。 步骤 1&#xff1a;更新软件源 首先…

Ubuntu环境基于Ollama部署DeepSeek+Open-Webui实现本地部署大模型-无脑部署

Ollama介绍 Ollama是一款简单好用的模型部署工具,不仅可以部署DeepSeek,市面上开源模型大部分都可以一键部署,这里以DeepSeek为例 官网 DeepSeek 版本硬件要求 安装Ollama 环境 sudo apt update sudo apt install curl sudo apt install lsof1.命令一键安装 在官网点击…

Angular 项目 PDF 批注插件库在线版 API 示例教程

本文章介绍 Angular 项目中 PDF 批注插件库 ElasticPDF 在线版 API 示例教程&#xff0c;API 包含 ① 导出批注后PDF数据&#xff1b;② 导出纯批注 json 数据&#xff1b;③ 加载旧批注&#xff1b;④ 切换文档&#xff1b;⑤ 切换用户&#xff1b;⑥ 清空批注 等数据处理功能…

Spring Boot 中利用 Jasypt 实现数据库字段的透明加密解密

1. 引言 1.1 什么是 Jasypt Jasypt(Java Simplified Encryption)是一个用于简化 Java 应用程序中加密操作的库。 1.2 为什么使用 Jasypt 简化加密操作:提供简单的 API 进行加密和解密。透明加密:自动处理加密和解密过程,无需手动干预。多种加密算法:支持多种加密算法,…

Linux的: /proc/sys/net/ipv6/conf/ 笔记250405

Linux的: /proc/sys/net/ipv6/conf/ /proc/sys/net/ipv6/conf/ 是 Linux 系统中用于 动态配置 IPv6 网络接口参数 的核心目录。它允许针对不同网络接口&#xff08;如 eth0、wlan0&#xff09;或全局设置&#xff08;all&#xff09;调整 IPv6 协议栈的行为。 它通过虚拟文件系…

Spring Cloud 框架为什么能处理高并发

Spring Cloud框架能够有效处理高并发场景&#xff0c;核心在于其微服务架构设计及多组件的协同作用&#xff0c;具体机制如下&#xff1a; 一、分布式架构设计支撑高扩展性 服务拆分与集群部署 Spring Cloud通过微服务拆分将单体系统解耦为独立子服务&#xff0c;每个服务可独…

无人机智慧路灯杆:智慧城市的‘全能助手’

在城市发展的进程中&#xff0c;智慧路灯杆作为智慧城市建设的关键载体&#xff0c;正逐步从传统的照明设备转型为集多种功能于一体的智能基础设施。无人机与智慧路灯杆的创新性融合&#xff0c;为城市管理和服务带来了全新的变革与机遇。 一、无人机智慧路灯杆的功能概述 照…

Libevent UDP开发指南

UDP 与 TCP 的核心区别 无连接:不需要建立/维护连接 不可靠:不保证数据包顺序和到达 高效:头部开销小,没有连接管理负担 支持广播/多播:可以向多个目标同时发送数据 一、基础UDP服务器实现 1. 创建 UDP 套接字 #include <event2/event.h> #include <event2/lis…

基于阿里云可观测产品构建企业级告警体系的通用路径与最佳实践

前言 1.1 日常生活中的告警 任何连续稳定运行的生产系统都离不开有效的监控与报警机制。通过监控&#xff0c;我们可以实时掌握系统和业务的运行状态&#xff1b;而报警则帮助我们及时发现并响应监控指标及业务中的异常情况。 在日常生活中&#xff0c;我们也经常遇到各种各样…

智能多媒体处理流水线——基于虎跃办公API的自动化解决方案

在内容爆炸的时代&#xff0c;多媒体文件处理&#xff08;图片压缩、视频转码、音频降噪&#xff09;已成为内容生产者的日常挑战。本文将演示如何基于虎跃办公的多媒体处理API&#xff0c;构建自动化处理流水线&#xff0c;实现&#xff1a; 批量文件智能分类格式自动转换质量…

01-STM32(介绍、工具准备、新建工程)p1-4

文章目录 工具准备和介绍硬件设备stm32简介和arm简介stm32简介STM32命名规则STM32选型STM32F103C8T6最小系统板引脚定义STM32启动配置STM32最小系统电路ARM简介 软件安装注册器件支持包安装ST-LINK驱动安装USB转串口驱动 新建工程创建stm32工程STM32工程编译和下载型号分类及缩…

【ABAP】REST/HTTP技术(一)

1、概念 1.1、SAP 如何提供 Http Service 如果要将 SAP 应用程序服务器 &#xff08;application server&#xff09;作为 http 服务提供者&#xff0c;需要定义一个类&#xff0c;这个类必须实现 IF_HTTP_EXTENSION 接口。IF_HTTP_EXTENSION 接口只有一个方法 HANDLE_REQUEST。…