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

20242817李臻《Linux⾼级编程实践》第二周

一、AI对学习内容的总结

第2章 Linux编程环境总结

1. GCC编译器

  • GCC(GNU Compiler Collection)是GNU项目的一部分,支持多种编程语言,包括C、C++、Java、Fortran、Ada等。
  • 编译过程:GCC将源程序转换为可执行程序的过程包括预处理、编译、汇编和链接四个步骤。
1.1 编译流程
  • 预处理:处理宏定义和头文件,生成.i文件
 gcc -E hello.c -o hello.i
  • 编译:生成汇编代码.s文件
gcc -S hello.i -o hello.s
  • 汇编:生成目标文件.o文件
gcc -c hello.s -o hello.o
  • 链接:生成可执行文件
gcc hello.o -o hello
1.2常用选项
  • 预处理控制
    • -E:仅进行预处理,输出到标准输出。
    • -Dname:定义宏name,值为1。
    • -Dname=definition:定义宏name,值为definition
    • -Uname:取消宏name的定义。
    • -undef:取消所有与操作系统和GCC相关的宏定义。
  • 编译及警告信息控制
    • -o filename:指定输出文件名。
    • -c:仅编译为目标文件,不进行汇编和链接。
    • -S:仅编译为汇编文件。
    • -Wall:显示所有警告信息。
    • -W:禁止所有警告信息。
    • -Werror:将所有警告信息转换为错误信息。
  • C语言标准控制
    • -ansi:使用ISO C90标准。
    • -std=c89:使用ISO C89标准。
    • -std=c99:使用ISO C99标准。
    • -std=gnu89:使用GNU扩展的ISO C89标准。
    • -std=gnu99:使用GNU扩展的ISO C99标准。
  • 程序调试及优化
    • -g:生成调试信息,用于GDB调试。
    • -O0:不进行优化(默认)。
    • -O1:基本优化。
    • -O2:进一步优化。
    • -O3:最高优化级别。
    • -Os:优化代码大小。
选项功能示例
-o指定输出文件名gcc -o hello hello.c
-c仅编译不链接gcc -c hello.c
-Wall显示所有警告信息gcc -Wall hello.c
-g生成调试信息gcc -g -o debug hello.c
-D定义宏gcc -DDEBUG -o prog
-I指定头文件搜索路径gcc -I./include
-l链接库文件gcc -lm(链接数学库)
1.3静态库与动态库
  • 静态库
    • 使用ar工具创建静态库文件(.a)。
    • 静态库在编译时将代码复制到可执行文件中。
    • 示例命令:
      gcc -c file.c
      ar rcs libname.a file.o
      
  • 动态库
    • 使用gcc -shared创建动态库文件(.so)。
    • 动态库在运行时动态加载,节省磁盘空间和内存。
    • 示例命令:
      gcc -fPIC -c file.c
      gcc -shared -o libname.so file.o
      
  • 静态库(.a文件):
# 生成目标文件
gcc -c lib1.c lib2.c
# 打包为静态库
ar rcs libmylib.a lib1.o lib2.o
# 使用静态库
gcc main.c -L. -lmylib -o main
  • 动态库(.so文件):
# 生成位置无关代码
gcc -fPIC -c lib1.c lib2.c
# 生成动态库
gcc -shared -o libmylib.so lib1.o lib2.o
# 使用动态库(需设置环境变量)
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
gcc main.c -L. -lmylib -o main

2. GDB调试器

2.1 基本使用
  • GDB(GNU Debugger)是GNU项目提供的调试工具,支持C、C++、Ada、Pascal等多种语言。
  • 主要功能
    • 启动程序并影响其行为。
    • 根据条件停止程序执行。
    • 检查程序崩溃时的状态。
    • 修改程序内部状态。
  • 编译时添加调试信息:
gcc -g -o debug_prog debug_prog.c
  • 启动GDB:
gdb debug_prog
2.2 常用命令
  • 启动调试
    • file <program>:加载可执行程序。
    • run:开始运行程序。
    • run <arguments>:传递参数运行程序。
  • 断点操作
    • break <location>:在指定位置设置断点。
    • delete breakpoints <n>:删除断点。
    • clear <location>:清除断点。
    • disable <n>:禁用断点。
    • enable <n>:启用断点。
  • 查看变量
    • print <variable>:打印变量值。
    • watch <variable>:监视变量变化。
  • 程序控制
    • step:单步进入函数。
    • next:单步跳过函数。
    • continue:继续运行到下一个断点。
    • start:开始执行程序,在main函数的第一条语句前停止。
  • 堆栈信息
    • backtrace:查看函数调用栈。
    • frame <n>:查看指定堆栈帧。
  • 其他命令
    • list:显示源代码。
    • info:显示程序状态。
    • set var <variable>=<value>:修改变量值。
    • quit:退出GDB。
选项功能示例
break设置断点b main 或 b 10
run启动程序r
next单步执行(不进入函数)n
step单步执行(进入函数)s
print打印变量值p var
backtrace查看函数调用栈bt
watch监控变量变化watch var
continue继续运行到下一个断点c
2.3 调试段错误
  • 段错误调试
    • 使用gcc -g编译程序。
    • 使用gdb加载程序并运行。
    • 使用backtrace查看函数调用栈。
    • 使用info查看程序状态。
  • 变量监视
    • 使用watch命令监视变量变化。
    • 使用print命令打印变量值。
  • 生成Core Dump文件:
ulimit -c unlimited
./crash_prog
  • 分析Core文件:
gdb crash_prog core

3. Make工具与Makefile

  • Make工具用于自动化编译过程,通过Makefile文件管理项目编译规则。
  • 主要功能
    • 自动检测源文件的变化。
    • 自动重新编译需要更新的文件。
    • 支持多目标文件的编译。
    • 支持条件编译和变量定义。
3.1 Makefile基本结构
# 定义变量
CC = gcc
CFLAGS = -Wall -g

# 默认目标
all: program

# 目标依赖和命令
program: main.o utils.o
    $(CC) $(CFLAGS) -o program main.o utils.o

# 隐式规则(自动推导.c -> .o)
main.o: main.c
utils.o: utils.c

# 清理规则
clean:
    rm -f *.o program
3.2 核心概念
  • 显式规则:明确指定目标、依赖和命令。
  • 隐式规则:自动推导(如.c编译为.o)。
  • 变量:简化重复内容(如$(CC))。
  • 伪目标:声明不生成文件的目标(如clean):
.PHONY: clean
3.3自动变量
变量含义
$@当前目标名称
$<第一个依赖文件
$^所有依赖文件(去重)
$?比目标新的依赖文件
3.4高级功能
  • 条件指令:
ifeq ($(OS),Linux)
    LIBS = -lpthread
else
    LIBS = -lws2_32
endif
  • 函数
# 查找所有.c文件
SRCS = $(wildcard *.c)
# 替换为.o文件
OBJS = $(patsubst %.c,%.o,$(SRCS))

总结

  • GCC:掌握编译流程、常用选项及库文件构建。
  • GDB:熟练使用断点、单步调试和Core文件分析。
  • Make:理解Makefile结构、变量与自动推导,提高项目管理效率。

二、对AI总结的反思和补充

一、GCC编译器

GCC是Linux下C语言的编译器,是GNU编译器集合

1. 静态库 vs 动态库的深入对比

特性静态库 (.a)动态库 (.so)
编译阶段代码直接嵌入可执行文件运行时动态加载
文件体积可执行文件较大可执行文件较小
部署难度无需额外配置需设置LD_LIBRARY_PATH或系统路径
更新维护需重新编译整个程序替换库文件即可生效
典型场景嵌入式开发、无依赖环境部署大型软件模块化开发

2. 高级编译选项

  • 优化级别
 gcc -O2 -o optimized_prog prog.c  # 平衡性能与编译速度
 gcc -Os -o size_opt_prog prog.c   # 优化代码体积
  • 调试符号保留
gcc -g3 -o debug_prog prog.c      # 支持宏调试(gdb中可展开宏)

3.常见问题

  • 头文件冲突:
    使用-I指定自定义头文件路径,避免与系统头文件冲突:
gcc -I./custom_include -o prog prog.c
  • 符号未定义:
    确保库顺序正确(依赖库放后面):
gcc prog.c -L. -lfoo -lbar       # libfoo依赖libbar时,libbar在后

二、GDB调试器

1.多线程调试技巧

  • 查看所有线程堆栈:
(gdb) thread apply all bt
  • 切换线程:
(gdb) thread 2                   # 切换到线程2

2.高级断点设置

  • 条件断点:
(gdb) break main.c:20 if i==5    # 当i=5时触发断点
  • 临时断点
(gdb) tbreak function_name       # 触发一次后自动删除

3.Core Dump深度分析

  • 生成完整调用链:
(gdb) bt full                   # 显示完整堆栈和局部变量
(gdb) info registers            # 查看寄存器状态

三、Makefile进阶

1.变量定义
  • 作用:变量用于简化Makefile的编写,避免重复代码,提高可维护性。
  • 类型
    • 递归展开变量:使用=赋值,变量值在使用时展开。
      CC = gcc
      CFLAGS = -Wall -g
      
    • 简单变量:使用:=赋值,变量值在定义时立即展开。
      CC := gcc
      
  • 使用场景
    • 在命令中通过$(变量名)使用变量,例如:
      main: main.o
          $(CC) -o main main.o $(CFLAGS)
      
2.隐式规则
  • 作用:隐式规则允许Make自动推导目标文件的生成规则,减少Makefile的编写工作量。
  • 示例
    • .c文件编译为.o文件:
      %.o: %.c
          $(CC) -c $< -o $@ $(CFLAGS)
      
    • 使用隐式规则简化目标文件的生成:
      main: main.o hello1.o hello2.o
          $(CC) -o main main.o hello1.o hello2.o $(CFLAGS)
      
3.伪目标
  • 伪目标
    • 作用:伪目标用于执行特定命令,避免与同名文件冲突,提高Makefile的灵活性。
    • 常见伪目标
      • all:用于编译所有目标。
      • clean:用于清理生成的文件。
      • install:用于安装生成的程序。
    • 示例
      .PHONY: all clean install
      
      all: main
      
      clean:
          rm -f *.o main
      
      install:
          cp main /usr/bin
      

三、学习思维导图

第二章

在这里插入图片描述

mindmap
  root((Linux编程环境))
    GCC
      编译器简介
        将源程序转换为可执行程序
        预处理、编译、汇编、链接
      常用选项
        预处理控制
          -E选项
          -Dname选项
        编译及警告信息控制选项
          -o选项
          -c选项
          -Wall选项
        C语言标准控制选项
          -ansi选项
          -std=选项
        搜索路径控制和链接选项
          -Idir选项
          -Ldir选项
      创建库文件
        静态库
        动态库
    GDB调试器
      使用方法
        编译时添加-g参数
        启动GDB
        常用命令
          list
          break
          run
          display
          step
          print
          continue
          quit
      调试实例
        段错误调试
        程序错误分析
    Make工具
      Makefile编写
        显式规则
        变量定义
        注释
      Makefile示例
        项目结构
        编译规则
      Make命令用法
        -f选项
        -n选项
        -d选项

四、基于AI的学习

1.关于Makefile

  • 我:
    我在学习Make和Makefile知识点,请你以苏格拉底的方式对我进行提问,一次一个问题
  • AI:
    你知道什么是Makefile,以及它在软件开发中起什么作用吗?
  • 我:
    Makefile 是一个用来告诉计算机如何编译和构建程序的文件,它和一个叫 make 的工具一起工作。它可以实现自动化编译,方便管理项目。
  • AI:
    既然Makefile可以实现自动化编译,那么你认为为什么我们需要自动化编译?手动编译有哪些局限性?
  • 我:
    自动化编译可以更方便地管理项目,手动编译耗时费力,同时人工的操作会增加编译时间
  • AI:
    既然自动化编译可以提高效率,那么你认为一个典型的Makefile应该包含哪些关键元素,才能实现有效的自动化编译?
  • 我:
    你的理解是什么
  • AI:
    目标(Targets):指定要生成的文件或执行的操作,比如编译生成的可执行文件或目标文件。
    依赖(Dependencies):列出目标所依赖的文件或其他目标,确保在目标构建之前这些依赖已经准备好。
    命令(Commands):定义如何从依赖生成目标的具体命令,通常是编译或链接指令。
    你认为为什么需要将目标、依赖和命令分开定义?这样做有什么好处?
  • 我:
    可以让项目具有清晰的逻辑结构,使得开发更加灵活,方便团队协作。针对我该知识点,我理解了吗?我的回答结束了,请对我的回答进行评价总结
  • AI:
    优点:
    理解基本功能:你知道Makefile用于自动化编译,并与make工具协同工作。
    认识自动化优势:你提到自动化编译节省时间、减少人工错误。
    理解结构:你认识到Makefile包含目标、依赖和命令,有助于项目管理和团队协作。
    可深入的地方:
    依赖关系:可以更具体说明Makefile如何通过时间戳检查避免不必要的重新编译。
    高级特性:探索变量、模式规则、条件判断等,编写更灵活的Makefile。
    实践:通过实际项目练习,直观理解其工作原理。
    总结:
    你对Makefile的基础掌握不错,接下来可以通过实践和学习高级特性进一步提升。继续加油!有问题随时提问。

2.关于GDB

  • 我:
    我在学习GDB知识点,请你以苏格拉底的方式对我进行提问,一次一个问题
  • AI:
    你知道GDB是用来做什么的吗?请简要描述它的主要功能。
  • 我:
    GDB是一款调试功能,能帮助程序员调试程序。
  • AI:
    你认为在调试程序时,GDB能够帮助程序员完成哪些具体的任务?或者说,GDB提供了哪些功能来辅助调试?
  • 我:
    设置断点、单步执行、查看变量、查看调用栈、修改变量等
  • AI:
    你能详细解释一下如何在GDB中设置断点吗?具体有哪些方法可以设置断点?
  • 我:
    1、break 文件名:行号
    2、break 函数名
    3、break *地址
    4、break 文件名:行号 if 条件
    5、tbreak 文件名:行号
  • AI:
    你提到可以使用 break 文件名:行号 if 条件 来设置条件断点。你能举一个具体的例子,说明在什么情况下使用条件断点会特别有用吗?
  • 我:
    假设你在调试一个程序,想找出变量 x 是何时变成负数的。你可以设置一个条件断点:
break 文件名:行号 if x < 0

这样,程序只有在变量 x 小于 0 时才会暂停,其他时候不会停。这样就能快速定位问题发生的位置,而不需要每次都手动检查变量值。

  • AI:
    在你提到的例子中,假设你已经设置了条件断点,并且程序在某个时刻暂停了。接下来,你会使用哪些GDB命令来进一步分析问题,并找出变量 x 变成负数的原因?

  • 我:
    使用print加设置断点、单步执行的方法,逐步排除出错的地方。我的回答结束了,请对我的回答进行评价总结。

  • AI:
    你的回答非常简洁,并且抓住了关键点!以下是对你回答的总结和评价:

  1. 明确目标:你清楚地指出了使用 print 命令来查看变量的值,这是调试过程中非常基础且重要的一步。
  2. 逐步排查:你提到了通过设置断点和单步执行来逐步排查问题,这是一种非常系统化的调试方法,能够帮助精确定位问题的根源。
  3. 简洁有效:你的回答虽然简短,但涵盖了调试的核心步骤,体现了你对GDB调试流程的基本理解。
    改进建议
  • 你可以进一步扩展一下具体的GDB命令,例如:
    • print x:查看变量 x 的当前值。
    • stepnext:单步执行代码。
    • backtrace:查看调用栈,了解程序是如何执行到当前断点的。
    • info locals:查看当前函数的所有局部变量。
  • 另外,可以结合具体场景,描述如何通过这些命令逐步缩小问题范围,最终找到 x 变成负数的原因。
    总的来说,你的回答已经抓住了调试的核心思路,继续保持这种系统化的思维方式,并在实践中不断积累经验,你会越来越熟练地使用GDB进行调试!

五、基于AI的代码实践

使用Gitee进行代码托管

仓库链接:

https://gitee.com/li-zhen1215/homework/tree/master/
在这里插入图片描述
在这里插入图片描述

例2-1

hello.c

#include<stdio.h>
void main()
{
    printf("hello,world\n");
}

实践展示:
在这里插入图片描述

例2-2

debug.c

【例 2-2】GCC -D 选项的使用,假设程序 debug.c 内容如下:
#include <stdio.h>
void main()
{
    int arr[10],i=0;
    for (i=0;i<10;i++)
    {
        arr[i]=i;
        if (DEBUG) // 使用了一个名为 DEBUG 的宏,该宏在编译的时候定义
        {
            printf("arr[%d]=%d\n",i,arr[i]);
        }
    }
}

实践展示:

在这里插入图片描述

例2-3

test.c

#include <stdio.h>

#define sum(a,b) a+b  // 宏定义
void main()
{
    int num=sum(1,2);
    printf("num=%d\n",num);
}
gcc -E -o test.i test.c

实践结果:
test.i:
在这里插入图片描述

例2-4

在这里插入图片描述

main.c

#include<stdio.h>
#include<math.h>
int main()
{
    printf("hello world\n");
    double pi=3.1415926;
    printf("sin(pi/2)=%f",sin(pi/2));
    return 0;
}

例2-5

calc.c

double aver(double,double);
double sum(double,double);

aver.c

#include "calc.h"
double aver(double num1,double num2)
{
    return (num1+num2)/2;
}

sum.c

sum.c 文件实现第二个函数:
#include "calc.h"
double sum(double num1,double num2)
{
    return (num1+num2);
}

实践结果:
在这里插入图片描述

例2-6

main.c

#include <stdio.h>
#include "calc.h"
int main(int argc, char* argv[]) {
    double v1, v2, m, sum2;
    v1 = 3.2;
    v2 = 8.9;
    m = aver(v1, v2);
    sum2 = sum(v1, v2);
    printf("The mean of %3.2f and %3.2f is %3.2f\n", v1, v2, m);
    printf("The sum of %3.2f and %3.2f is %3.2f\n", v1, v2, sum2);
    return 0;
}

实践结果:

在这里插入图片描述

例2-7

example.c

3)GDB 常用命令详解
【例 2-7】下面以 example.c 源程序为例,演示 GDB 的基本调试过程,首先使用命令 gcc -o -g exam example.c 编译生成可执行程序。
#include <stdio.h>
void debug(char *str)
{
    printf("debug information: %s\n", debug);
}
main()
{
    int i,j;
    j=0;
    for (i=0;i<10;i++)
    {
        j+=5;
        printf("now a==%d\n",j);
        debug("xxxxxxxxxxxx");
    }
}

然后在同一目录下输入 GDB 命令,在出现 GDB 的提示符后,执行 file exam 命令,加载 exam 程序以进行调试。如下所示:
(gdb) file exam
Reading symbols from /home/cosmos/book/chapter2/exam...done.

实践结果:

在这里插入图片描述

例2-8

#include <stdio.h> 
#include <stdlib.h>
void recurse(void)
{
    static int i;
    if ( ++i == 3 )
        abort();
    else
        recurse();
}
int main(int argc,char **argv)
{
    recurse();
}

实践结果

在这里插入图片描述

例2-9

test.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>  // 确保包含了 string.h 头文件

int main() {
    char string[256];  // 定义一个足够大的数组来存储输入的字符串

    printf("Please input a string: ");
    fgets(string, sizeof(string), stdin); // 使用 fgets 代替 gets
    string[strcspn(string, "\n")] = 0; // 去除换行符

    printf("\nThe string is: %s\n", string);
    return 0;
}

实践截图:
在这里插入图片描述

例2-10

hello1.h

/*hello1.h*/
#ifndef HELLO_1_H          // 预编译命令,防止多次包含头文件
#define HELLO_1_H
void hello1(char *mess);    // 打印 mess 的内容
#endif

hello2.h

/*hello2.h*/
#ifndef HELLO_2_H          // 预编译命令,防止多次包含头文件
#define HELLO_2_H
void hello2(char *mess);    // 打印 mess 的内容
#endif

hello1.c

#include "hello1.h"
#include <stdio.h>  

void hello1(char *mess) {
    printf("This is hello1 print %s\n", mess);
}

hello2.c

#include "hello2.h"
#include <stdio.h>  

void hello2(char *mess) {
    printf("This is hello2 print %s\n", mess);
}

main.c

/*main.c*/
#include "hello1.h"
#include "hello2.h"
int main(int argc, char **argv)
{
    hello1("hello"); // 执行 hello1 函数
    hello2("world"); // 执行 hello2 函数
}

Makefile

#Makefile
main:main.o hello1.o hello2.o
    gcc -o main main.o hello1.o hello2.o
main.o:main.c hello1.h hello2.h
    gcc -c main.c
hello1.o:hello1.c hello1.h
    gcc -c hello1.c
hello2.o:hello2.c hello2.h
    gcc -c hello2.c
clean:
    rm main hello1.o hello2.o main.o

实践截图:
在这里插入图片描述

课后习题

1. 静态链接库和动态链接库之间的相同点和不同点

相同点:

  • 都是共享代码的方式,避免重复编写和编译相同的代码。
  • 允许程序使用库中定义的函数和变量。

不同点:

  • 静态链接库在编译时被复制到最终的可执行文件中,增加可执行文件的大小,运行时不需要库文件。
  • 动态链接库在程序运行时加载,减小可执行文件的大小,运行时需要库文件。
  • 静态链接库更新需要重新编译所有使用该库的程序;动态链接库更新只需替换库文件,无需重新编译程序。

2. Make命令工具如何确定哪些文件需要重新生成,而哪些不需要生成

  • Make工具通过比较目标文件和其依赖文件的时间戳来确定。
  • 如果目标文件不存在或其修改时间晚于任一依赖文件,则需要重新生成。
  • 如果目标文件比所有依赖文件新,则不需要重新生成。
  • Makefile中的规则和变量也会影响哪些文件需要重新生成。

3. Make中的伪目标的作用是什么

  • 伪目标用于定义不对应实际文件的目标。
  • 用于执行操作,如构建多个目标或执行复杂构建步骤。
  • 避免与实际文件名冲突,确保Make能执行所需操作。
  • 伪目标通常以.PHONY声明,例如.PHONY: clean,确保make clean执行清理操作。

4./5.用隐式规则实现图示题目

在这里插入图片描述

Makefile

# 目标文件
TARGET = menu
OBJS = menu.o music.o picture.o

# 编译器
CC = gcc
CFLAGS = -Wall -g

# 生成可执行文件
$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $(TARGET) $(OBJS)

# 生成 .o 文件的规则
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

# 清除编译文件
.PHONY: clean install
clean:
	rm -f $(TARGET) $(OBJS)

# 安装可执行文件
install: $(TARGET)
	cp $(TARGET) /usr/bin/

menu.c

#include <stdio.h>
#include "menu.h"

int main() {
    printf("Menu module\n");
    music();
    picture();
    return 0;
}

menu.h

#ifndef MENU_H
#define MENU_H

void music();
void picture();

#endif

music.c

#include <stdio.h>
#include "menu.h"

void music() {
    printf("Music module\n");
}

picture…c

#include <stdio.h>
#include "menu.h"

void picture() {
    printf("Picture module\n");
}

实践结果:

在这里插入图片描述


六、学习实践过程遇到的问题与解决方式

问题1,不太会用Gitee仓库

向AI提出问题:
给我生成一份详细的Gitee使用教程,在Ubuntu系统上。
根据DeepSeek给出的教程,结合CSDN上的博客,一点点进行实操。
第一次上传的时候,直接把当前目录的所有文件上传到了仓库,显得很混乱。
后面向AI了解了git的一些概念,成功解决问题。

问题2,不习惯使用Makefile的自动化编译

使用Makefile时经常出现各种错误,比如链接库失败,依赖缺失等。当程序报错的时候,可以将报错信息发给AI,AI会分析报错原因,并提供正确的做法,如:

编译错误:undefined reference to xxx
链接错误:library not found
依赖问题:missing dependency

AI还会生成各种学习资源,以及对当前更好的修改方法。而且AI可以生成基础语法教程,如果对哪一种命令感到疑惑,也可以问AI,让AI生成具体用法并给出示例,学习事半功倍。


参考资料

  • AI工具(你使用的AI工具及其链接)

    • 问小白
    • Kimi
  • 图书

    • 《Linux编程基础.李养群》电子版
  • 网站

    • CSDN

“20242817李臻 原创作品转载请注明出处 《Linux高级编程实践》”


http://www.kler.cn/a/576547.html

相关文章:

  • WordPress报502错误问题解决-php-fpm-84.service loaded failed failed LSB: starts php-fpm
  • 为AI聊天工具添加一个知识系统 之133 详细设计之74通用编程语言 之4 架构及其核心
  • 【SegRNN 源码理解】self.revIN可逆实例标准化
  • Elasticsearch:“Your trial license is expired”
  • 乐鑫打造全球首款 PSA Certified Level 2 RISC-V 芯片
  • Qt 实现绘图板(支持橡皮擦与 Ctrl+Z 撤销功能)[特殊字符]
  • React Native 0.76 升级后 APK 体积增大的原因及优化方案
  • linux的文件系统及文件类型
  • 护照阅读器在旅游景区流程中的应用
  • 深度学习网格搜索实战
  • GPO 配置的 4 种常见安全错误及安全优化策略
  • 机器学习(李宏毅)——Life-Long Learning
  • 在 Docker 中安装并配置 Nginx
  • Service 无法访问后端 Pod,如何逐步定位问题
  • C++ `bitset` 入门指南
  • 蓝桥杯P17153-班级活动 题解
  • Elastic如何获取当前系统时间
  • 【算法方法总结·四】字符串操作的一些技巧和注意事项
  • Chrome 扩展开发:Chrome 扩展的作用和开发意义(一)
  • Ollama 框架本地部署教程:开源定制,为AI 项目打造专属解决方案!