目录

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

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
      

三、学习思维导图

第二章

https://i-blog.csdnimg.cn/direct/bd49b2964dea4fdd9268309419e75ca8.png

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://i-blog.csdnimg.cn/direct/e5433f6f7fc74e058b47f8801af8bb1a.png

https://i-blog.csdnimg.cn/direct/66266e3087ef43f0bdad2441c253e9d6.png

例2-1

hello.c

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

实践展示:

https://i-blog.csdnimg.cn/direct/80f08253c3224d77a58e0b8314954d70.png

例2-2

debug.c

【例 2-2GCC -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]);
        }
    }
}

实践展示:

https://i-blog.csdnimg.cn/direct/6e1012f92a92421296f70e817b69c6b3.png

例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:

https://i-blog.csdnimg.cn/direct/1e78b15690154cdf8e5a380e471bfc93.png

例2-4

https://i-blog.csdnimg.cn/direct/71dd89c84dd0443da746795327e9257e.png

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);
}

实践结果:

https://i-blog.csdnimg.cn/direct/a8c18167faf24682a38e4c888faae885.png

例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;
}

实践结果:

https://i-blog.csdnimg.cn/direct/e77725c0ee6542be9c96d7a99203815f.png

例2-7

example.c

3GDB 常用命令详解
【例 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.

实践结果:

https://i-blog.csdnimg.cn/direct/f5b739abe32f4573834c8c8ea05340cf.png

例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();
}

实践结果

https://i-blog.csdnimg.cn/direct/5da5147fe7d3446d82c216c6652440c5.png

例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;
}

实践截图:

https://i-blog.csdnimg.cn/direct/93277a8685584c77859ff79e8f77f5dd.png

例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

实践截图:

https://i-blog.csdnimg.cn/direct/925e2ad36f1f406fbc0688062e0c9dbb.png

课后习题

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

相同点:

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

不同点:

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

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

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

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

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

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

https://i-blog.csdnimg.cn/direct/d89aa5b5ee14476b894e31c07b2fc707.png

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");
}

实践结果:

https://i-blog.csdnimg.cn/direct/8ce5828dda2743fd81cda71c6dd0bc40.png


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

问题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工具及其链接)

  • 图书

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


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