Linux程序开发(三):MakeFile编程及Githup项目编码

news2024/11/17 7:52:32

Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊!

喜欢我的博客的话,记得点个红心❤️和小关小注哦!您的支持是我创作的动力!数据源存放在我的资源下载区啦!

Linux程序开发(三):MakeFile编程及Githup项目编码

目录

  • Linux程序开发(三):MakeFile编程及Githup项目编码
    • 1. 问答题
      • 1.1. C语言程序test.c如下,编译并执行该程序。
      • 1.2. 编译以下程序并运行
      • 1.3. 编译以下程序
      • 1.4. 以下有两个文件:
      • 1.5. 以下源文件gdb3.c编译成执行文件gdb3,请在不直接运行的情况下,使用gdb调试,确认执行结果。将调试过程写下来,调试过程截图。
      • 1.6. github上的一个[项目](https://github.com/literaryno4/Makefile_tutorial)源代码目录如下:
      • 1.7. 分析静态链接库与动态链接库的优缺点
    • 2. 编程题
      • 2.1. 编写程序实现`选择排序`、 `冒泡排序`、 `快速排序`
      • 2.2. 编写Makefile文件实现上一题自动编译,要求可以用make命令实现:
      • 2.3. 小熊有很多苹果,每一天小熊会数出自己的苹果个数 n。如果 n 是偶数,小熊就会吃掉 n/2个苹果,如果 n 是奇数,小熊就会吃掉 (n+1)/2 个苹果。现在小熊吃了 k 天,还剩下最后一个苹果,现在小熊想知道 k 天前一共有多少苹果。当然,可能性不止一种,所以请你编写代码帮小熊计算出 k 天前他的苹果数量有多少种可能?

1. 问答题

1.1. C语言程序test.c如下,编译并执行该程序。

#include <stdio.h>

int main(int argc, char *argv[])
{
        int i;

        printf("Number of args:%d, args are:\n", argc); // 打印命令行参数的数量
        for(int i=0;i<argc;i++)
                printf("args[%d] %s\n", i, argv[i]); // 打印每个命令行参数的索引和内容
        fprintf(stderr, "This message is sent to stderr.\n"); // 将一条消息输出到标准错误流stderr中

        return 0;
}

请问,先后执行./test abc 234 2> a.txt./test abc 234 >> a.txt命令后,文件a.txt中的内容是什么?

屏幕上输出什么?

(1)在linux上运用gcc编译器来编译test.c

gcc编译器编译:gcc test.c -o test -std=c99

# C99是C语言的一个版本,它为循环的初始化部分引入了在 for 循环中声明变量的能力。然而,旧版本的 C 语言标准不允许这样做。GCC 编译器默认按照旧版本的 C 语言标准进行编译,因此需要使用 -std=c99 或 -std=gnu99 选项来告诉编译器使用 C99 标准编译代码。

在这里插入图片描述

(2)执行./test abc 234 2> a.txt,观察屏幕和a.txt文件==(标准错误流)==

# 在命令行中,> 符号用于将命令的输出重定向到文件。而 2> 表示将标准错误重定向到文件。
# 输入 ./test abc 234 2> a.txt 时:
# ./test abc 234 是要执行的命令,abc 和 234 是传递给该命令的参数。
# 2> 表示将标准错误重定向。
# a.txt 是要重定向到的文件。
# 因此,命令 ./test abc 234 的标准输出被打印到屏幕上,而标准错误被重定向到了名为 a.txt 的文件。

# 屏幕上输出了:
args[0] ./test
args[1] abc
args[2] 234

# a.txt 文件里面内容是:
This message is sent to stderr

在这里插入图片描述

(3)执行./test abc 234 >> a.txt,观察屏幕和a.txt文件==(标准输出流)==

# 屏幕上输出了:
This message is sent to stderr.

# a.txt文件里面的内容是: 
This message is sent to stderr.
Number of args:3, args are:
args[0] ./test
args[1] abc
args[2] 234

# 这个结果是因为使用了 >> 操作符来将命令的输出追加到文件 a.txt 中,而没有覆盖原有的内容。>> 操作符会将输出数据追加到文件末尾,而不是覆盖之前的数据。

# 运行命令 ./test abc 234 >> a.txt 时,./test 命令的标准输出被追加到了文件 a.txt 的末尾,而标准错误则仍然被发送到屏幕上。因此,在终端上会看到一行 This message is sent to stderr. 的输出。

# 同时,./test 程序在输出参数时,将一些信息发送到了标准错误流(stderr),而不是标准输出流(stdout)。这些数据仍然被发送到了终端上,并没有被重定向到文件中。

# 最后,使用 cat a.txt 命令查看文件内容时,会发现文件中已经存在了一行 This message is sent to stderr. 的文本。这是因为该行数据是之前执行命令 ./test abc 234 >> a.txt 时输出的,已经被追加到了文件末尾。而接下来显示的是 ./test 命令的标准输出数据,即程序输出的参数信息。

在这里插入图片描述

1.2. 编译以下程序并运行

// gdb1.c

#include <stdio.h>

unsigned short int *p; // 声明一个名为 p 的 unsigned short int 型指针变量

void hello(void)
{
    *p = (unsigned short int)"Hello GDUFE"; 
    // 将字符串 "Hello GDUFE" 的地址转换为 unsigned short int 类型并赋值给 p 指针所指向的内存
}

int main(void)
{
    hello(); // 调用 hello() 函数

    return 0; // 返回 0,表示程序正常结束
}

将上面程序编译为gdb1程序,编译时有警告,运行结果出错,请采用gdb调试器找出原因,写明过程,必要时截图。

(1)用gcc编译器编译程序,出现报错现象

gcc gdb1.c -o gdb1 -std=c99

# 在代码中,将字符串的地址转换为 unsigned short int 类型,并将其赋值给 *p。然而,这样的类型转换是不正确的,因为指针和整数的大小不同。编译器给出的警告信息是在编译过程中发现的问题,它提醒可能存在类型不匹配的错误。

(2)启动gdb调试器

gdb gdb1

(3)在 gdb 中运行程序,并设置断点在 hello 函数内部

break hello
run

(4)当程序停在断点处时,可以使用 print 命令打印变量的值

print p

在这里插入图片描述

(5)通过以上步骤,你会发现 p 的值是一个随机的地址,因为它未被初始化。

# 修复这个问题的方法是使用合适的指针类型,并且为指针分配合适的内存空间,以下是修改后的代码

// gdb2.c

#include <stdio.h>
#include <stdlib.h>

char* p;

void hello(void)
{
    p = "Hello GDUFE";
}

int main(void)
{
    hello();

    printf("%s\n", p);

    return 0;
}

# 这样修改后,再使用 gcc 编译器运行代码,会发现程序正常运行而不再出现警告信息。

在这里插入图片描述

1.3. 编译以下程序

// gdb2.c

// gdb2.c

#include <stdio.h>

#define MAX 1000    // 定义 MAX 常量为 1000,表示计算的上限

int main(int argc, char *argv[])
{
        int max = MAX;  // 定义并初始化变量 max 为 MAX 常量的值
        int sum = 0;    // 定义并初始化变量 sum0
        int i = 1;      // 定义并初始化变量 i 为 1

        while(i <= max) // 循环条件:i 不超过 max
                sum += i++;  // 累加 i 的值,并将 i 自增 1

        printf("sum=%d\n", sum);    // 输出 sum 的值

        return 0;
}

以上程序如果想在执行过程中改变,实现sum等于从1加到999,然后再加10000。应该如何做?

提示:采用gdb调试,实现,当变量i==999时,设置变量i的值为10000,也就是实现从1加到999,然后再加10000。

写出过程,必要时截图。

(1)使用gcc编译器编译程序

gcc -g gdb2.c -o gdb2   // 编译源代码,并生成可执行文件 gdb2

在这里插入图片描述

(2) 启动 gdb 并加载可执行文件

gdb gdb2 

在这里插入图片描述

(3)设置断点在循环结束后,即 while 循环条件为假时

break gdb2.c:12   // 设置断点在第 12 行

在这里插入图片描述

(4)运行程序并开始调试

run

在这里插入图片描述

(5)当程序停在断点处时,修改变量 i 的值为 10000,使其继续执行循环

set variable i = 10000   // 修改变量 i 的值为 10000
continue   // 继续执行程序

在这里插入图片描述

(6)编译程序,输出结果

./gdb2

在编译并运行该程序后,最终的输出结果应为 sum=5005000。

这是因为程序通过 while 循环将变量 i 从1累加到 max(即1000),并将每次累加的结果累加到变量 sum 中。循环结束后,变量 sum 的值即为从1到1000的累加和。

在程序的最后一行使用 printf 函数将结果输出到标准输出流(通常是控制台)。因此,当运行这个程序时,它会打印出 sum=5005000。

在这里插入图片描述

1.4. 以下有两个文件:

  • myhead.h 在/home/linux/目录下
  • myapp.c 在/home/linx/myapp/目录下

在不改变源文件位置,以及不改变源文件内容的情况下,请编译以下程序为myapp执行文件:

// myhead.h

#ifndef _MYHEDA_H
#define _MYHEAD_H
#include <stdio.h>
#include <math.h>
#endif

// myapp.c

#include "myhead.h"

void main()
{
        double angle = 43.78;

        printf("sin(43.78)=%lf, cos(43.78)=%lf\n", sin(angle), cos(angle));
}

(1)准备文件资料

在这里插入图片描述

(2)使用gcc编译器编译程序

命令行:gcc -I /home/linux/ -o myapp /home/linux/myapp.c -lm

添加了 -lm 选项来链接数学库。数学库是使用 -lm 进行链接的,以提供对数学函数 cos 和 sin 的支持。

在这里插入图片描述

(3)运行代码,得到结果

./myapp

在这里插入图片描述

1.5. 以下源文件gdb3.c编译成执行文件gdb3,请在不直接运行的情况下,使用gdb调试,确认执行结果。将调试过程写下来,调试过程截图。

选做

// gdb3.c

#include <stdio.h>

int main()
{
        union{
                int x[2];
                long y;
                char z[4];
                float l;
        } t;

        t.x[0] = 0x41;
        t.x[1] = 0x42;

        printf("%lx\n",t.y);
        printf("%c\n",t.z[0]);
        printf("%f\n",t.l);

        return 0;
}

(1)需要使用 -g 选项来在编译时加入调试信息

gcc -g -o gdb3 gdb3.c

在这里插入图片描述

(2)启动 GDB 并加载 gdb3 可执行文件

gdb gdb3

在这里插入图片描述

(3)在main处设置断点,并开始执行程序,程序会暂停在第一条语句前

break main
run

在这里插入图片描述

(4)使用以下命令逐语句地执行程序,并查看变量的值

next
print t.y
print t.z[0]
print t.l

在这里插入图片描述

1.6. github上的一个项目源代码目录如下:

├── include                  # 本文件下包含构建目标文件所需的头文件
    │   ├── become_daemon.h
    │   ├── error_functions.h
    │   ├── get_num.h
    │   ├── inet_sockets.h
    │   └── tlpi_hdr.h
    ├── lib                      # 本文件夹下包含构建目标文件所需的库文件和依赖文件
    │   ├── become_daemon.c
    │   ├── ename.c.inc
    │   ├── error_functions.c
    │   ├── get_num.c
    │   └── inet_sockets.c
    └── src                      # 本文件夹包含项目的源文件、Makefile、目标文件以及可执行文件
        ├── obj
        │   ├── become_daemon.o
        │   ├── client.o
        │   ├── error_functions.o
        │   ├── get_num.o
        │   ├── inet_sockets.o
        │   └── server.o
        ├── Makefile
        ├── client
        ├── client.c
        ├── server
        └── server.c

该源代码目录编译方法:

  1. 生成的目标文件:
gcc -c -o obj/error_functions.o ../lib/error_functions.c 
gcc -c -o obj/get_num.o ../lib/get_num.c 
gcc -c -o obj/inet_sockets.o ../lib/inet_sockets.c 
gcc -c -o obj/become_daemon.o ../lib/become_daemon.c 
gcc -c -o obj/client.o client.c 
gcc -c -o obj/server.o server.c
  1. 链接目标文件生成可执行文件:
gcc -o client obj/client.o  obj/error_functions.o  obj/get_num.o  obj/inet_sockets.o  obj/become_daemon.o 
gcc -o server obj/server.o  obj/error_functions.o  obj/get_num.o  obj/inet_sockets.o 

请编写Makefile实现编译要求。

选做

# 编译器和编译选项
CC := gcc
CFLAGS := -Wall -Werror

# 源文件和目标文件路径
SRC_DIR := src
OBJ_DIR := $(SRC_DIR)/obj
LIB_DIR := lib

# 需要生成的目标文件
OBJS := $(OBJ_DIR)/client.o \
        $(OBJ_DIR)/server.o \
        $(OBJ_DIR)/error_functions.o \
        $(OBJ_DIR)/get_num.o \
        $(OBJ_DIR)/inet_sockets.o \
        $(OBJ_DIR)/become_daemon.o

# 编译可执行文件
all: client server

client: $(OBJ_DIR)/client.o $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

server: $(OBJ_DIR)/server.o $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

# 编译目标文件
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
	$(CC) $(CFLAGS) -c -o $@ $<

# 创建目标文件夹
$(OBJ_DIR):
	mkdir -p $@

# 清理生成的目标文件和可执行文件
clean:
	rm -rf $(OBJ_DIR) client server

.PHONY: all clean

注意:将上面的代码保存为 Makefile,然后在命令行中进入源代码目录,并执行 make 命令即可编译生成可执行文件 client 和 server。执行 make clean 可以清理生成的目标文件和可执行文件。

1.7. 分析静态链接库与动态链接库的优缺点

静态链接库和动态链接库是两种常见的库文件类型。它们各具有优缺点,下面分别进行分析:

一、静态链接库:静态链接库生成的是一个目标文件(以 .a 为扩展名),它包含了链接时需要用到的一些代码和数据。这意味着在使用静态链接库的程序被编译成可执行文件时,库中的所有代码和数据都会被复制到可执行文件中,称为静态链接。

1.静态链接库的优点包括:

(1)执行速度快:静态链接库的代码和数据在编译时就被全部加载到可执行文件中,相比动态链接库需要运行时再加载,因此程序执行时更快。
(2)稳定性高:因为静态链接库的代码和数据已经被复制到可执行文件中,程序执行时不受外部库文件版本、路径等的影响,因此更加稳定。

2.静态链接库的缺点包括:

(1)可执行文件较大:静态链接库的所有代码和数据都被复制到可执行文件中,因此可执行文件体积较大,如果程序依赖多个静态链接库,体积会更大。
(2)需要重新编译:如果要更新静态链接库,需要重新编译整个程序才能生效,这会增加工作量。

二、动态链接库:动态链接库生成的是一个共享库文件(以 .so 为扩展名),它包含了需要在运行时才能确定的一些代码和数据。在使用动态链接库的程序被编译成可执行文件时,只会在可执行文件中保留对动态链接库的引用,称为动态链接。

1.动态链接库的优点包括:

(1)可执行文件较小:动态链接库只在运行时加载,因此可执行文件只需要保留对动态链接库的引用即可,不会增加可执行文件的体积。
(2)更新方便:如果要更新动态链接库,只需要替换库文件即可,不需要重新编译整个程序。

2.动态链接库的缺点包括:

(1)执行速度稍慢:动态链接库需要在运行时加载,因此程序执行时速度稍慢。
(2)稳定性略低:因为动态链接库的代码和数据没有被复制到可执行文件中,程序执行时需要依赖外部库文件,如果外部库文件版本、路径等不正确,可能会导致程序出错。

2. 编程题

2.1. 编写程序实现选择排序冒泡排序快速排序

要求:

键盘输入20个数值进行排序;

然后再输入0、1、2中的一个数值,分别表示采用选择排序冒泡排序还是快速排序来排序;

输出从小到大排序结果。

选择排序冒泡排序快速排序采用三个不同源文件和头文件编写,编译时先将这些源文件编译成libmysort.a静态库,然后再编译主程序。

(1)select_sort.c(选择排序)

#include "mysort.h"

void selectSort(int arr[], int n) {
    int i, j, minIndex, temp;
    for (i = 0; i < n - 1; i++) {
        minIndex = i;
        for (j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        if (minIndex != i) {
            temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
}

(2)bubble_sort.c(冒泡排序)

#include "mysort.h"

void bubbleSort(int arr[], int n) {
    int i, j, temp;
    for (i = 0; i < n - 1; i++) {
        for (j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

(3)quick_sort.c(快速排序)

#include "mysort.h"

void quickSort(int arr[], int low, int high) {
    int i, j, pivot, temp;
    if (low < high) {
        pivot = low;
        i = low;
        j = high;
        while (i < j) {
            while (arr[i] <= arr[pivot] && i < high) {
                i++;
            }
            while (arr[j] > arr[pivot]) {
                j--;
            }
            if (i < j) {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        temp = arr[pivot];
        arr[pivot] = arr[j];
        arr[j] = temp;
        quickSort(arr, low, j - 1);
        quickSort(arr, j + 1, high);
    }
}

(4)mysort.h(头文件)

#ifndef MYSORT_H
#define MYSORT_H

void selectSort(int arr[], int n);
void bubbleSort(int arr[], int n);
void quickSort(int arr[], int low, int high);

#endif

(5)main.c(主程序)

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

int main() {
    int arr[20];
    int i, option;

    printf("请输入20个数值:\n");
    for (i = 0; i < 20; i++) {
        scanf("%d", &arr[i]);
    }

    printf("请选择排序算法(0:选择排序,1:冒泡排序,2:快速排序):\n");
    scanf("%d", &option);

    switch(option) {
        case 0:
            selectSort(arr, 20);
            printf("选择排序结果:");
            break;
        case 1:
            bubbleSort(arr, 20);
            printf("冒泡排序结果:");
            break;
        case 2:
            quickSort(arr, 0, 19);
            printf("快速排序结果:");
            break;
        default:
            printf("无效的选项\n");
            return 0;
    }

    for (i = 0; i < 20; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

在这里插入图片描述

(6)编译静态库文件

# 这条命令将 select_sort.c 文件编译为目标文件 select_sort.o。-c 选项告诉编译器只进行编译而不进行链接。
gcc -c select_sort.c 

# 这条命令将 bubble_sort.c 文件编译为目标文件 bubble_sort.o,同样使用了 -c 选项。
gcc -c bubble_sort.c

# 这条命令将 quick_sort.c 文件编译为目标文件 quick_sort.o,同样使用了 -c 选项。
gcc -c quick_sort.c

# 这条命令使用 ar 工具将目标文件 select_sort.o、bubble_sort.o 和 quick_sort.o 打包成一个静态库文件 libmysort.a。
# ar 是一个用于创建、修改和提取归档文件(静态库)的工具。
# rcs 是 ar 命令的选项,其中 r 表示插入(替换)文件到归档文件中,c 表示创建归档文件,s 表示创建索引。
ar rcs libmysort.a select_sort.o bubble_sort.o quick_sort.o

在这里插入图片描述

(7)编译主程序

# 这条命令是一个编译和链接命令,用于将 main.c 文件与前面生成的静态库文件 libmysort.a 进行链接,并生成可执行文件 sort。

# 下面是该命令中各个部分的含义:

# gcc main.c:这部分表示将 main.c 文件作为输入,进行编译。

# -o sort:这部分表示将生成的可执行文件命名为 sort,即输出文件名为 sort。

# -L.:这部分表示在当前目录下搜索链接时需要的库文件。-L 选项告诉链接器去指定的路径寻找库文件,. 表示当前目录。

# -lmysort:这部分表示要链接的库文件的名称。-l 选项告诉链接器链接指定的库文件,mysort 是库文件的名称(去掉 lib 前缀和 .a 后缀)。

#综合起来,这条命令的作用是将 main.c 编译为目标文件,然后与 libmysort.a 进行链接生成可执行文件 sort。链接过程中会使用 mysort 库中定义的函数和变量。最终生成的可执行文件 sort 可以运行并执行程序中的代码。

gcc main.c -o sort -L. -lmysort

在这里插入图片描述

(8)运行可执行文件

./sort

在这里插入图片描述

2.2. 编写Makefile文件实现上一题自动编译,要求可以用make命令实现:

直接编译成执行文件

(1)编写Makefile文件

# 编译器和编译选项
CC = gcc
CFLAGS = -Wall -Wextra

# 静态库和动态库名称
LIB_NAME = mysort
STATIC_LIB = lib$(LIB_NAME).a
DYNAMIC_LIB = lib$(LIB_NAME).so

# 源文件和目标文件
SRCS = main.c select_sort.c bubble_sort.c quick_sort.c
OBJS = $(SRCS:.c=.o)

# 默认目标:编译可执行文件
all: sort sort_static sort_dynamic

# 目标1:编译静态链接库库和可执行文件
sort_static: $(OBJS) $(STATIC_LIB)
	$(CC) $(CFLAGS) -o $@ $(OBJS) -L. -l$(LIB_NAME)

$(STATIC_LIB): select_sort.o bubble_sort.o quick_sort.o
	ar rcs $@ $^

# 目标2:编译动态链接库库和可执行文件
CFLAGS_DYNAMIC = $(CFLAGS) -fPIC
sort_dynamic: $(OBJS) $(DYNAMIC_LIB)
	$(CC) $(CFLAGS) -o $@ $(OBJS) -L. -l$(LIB_NAME)

$(DYNAMIC_LIB): select_sort.o bubble_sort.o quick_sort.o
	$(CC) $(CFLAGS_DYNAMIC) -shared -o $@ $^

# 目标3:编译可执行文件
sort: main.o $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

# 生成main.o文件
main.o: main.c mysort.h
	$(CC) $(CFLAGS) -c $<

# 目标4:清理中间文件和可执行文件
clean:
	rm -f $(OBJS) main.o $(STATIC_LIB) $(DYNAMIC_LIB) sort sort_static sort_dynamic

# 目标5:一次性编译三种可执行文件
all-in-one: all

(2)直接编译为执行文件

make sort

在这里插入图片描述

采用静态链接库编译成执行文件

(1)先删除后缀名为.o的文件以及可执行文件

rm -rf bubble_sort.o main.o quick_sort.o select_sort.o sort

(2)采用静态链接库编译成执行文件

make sort_static

在这里插入图片描述

采用动态链接库编译成执行文件

(1)先删除后缀名为.o和.a的文件,以及可执行文件

rm -rf bubble_sort.o main.o quick_sort.o select_sort.o sort_static libmysort.a

(2)采用动态链接库编译成执行文件

make sort_dynamic

在这里插入图片描述

清理现场,恢复源代码初始状态

make clean

在这里插入图片描述

一次性编译成三种执行文件

make all-in-one

在这里插入图片描述

2.3. 小熊有很多苹果,每一天小熊会数出自己的苹果个数 n。如果 n 是偶数,小熊就会吃掉 n/2个苹果,如果 n 是奇数,小熊就会吃掉 (n+1)/2 个苹果。现在小熊吃了 k 天,还剩下最后一个苹果,现在小熊想知道 k 天前一共有多少苹果。当然,可能性不止一种,所以请你编写代码帮小熊计算出 k 天前他的苹果数量有多少种可能?

输入输出样例1:

输入:1

输出:2

输入输出样例2:

输入:5

输出:32

代码样式:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int countApple(int k) {
    if (k == 0) {
        return 1;
    }

    int prevCount = countApple(k - 1);
    return prevCount * 2;
}

int main() {
    int k;
    printf("请输入小熊吃了几天的苹果:");
    scanf("%d", &k);

    int result = countApple(k);
    printf("小熊在%d天前可能拥有的苹果数量的种类数为:%d\n", k, result);

    return 0;
}

结果显示1:

在这里插入图片描述

结果显示2:

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

海外私人IP和原生IP有什么区别,谁更有优势?

一、什么是海外私人IP&#xff1f;什么是原生IP&#xff1f; 1、海外私人IP&#xff1a; 海外私人IP是由专门的服务提供商提供的IP地址&#xff0c;这些IP地址通常与特定地理位置或国家相关联。这些IP地址独享私人而不用与其他用户共享。海外私人IP访问特定国家或地区的网站&am…

新定义RD8T36P48使用USCI0的TWI功能点亮OLED

时间不多&#xff0c;因此先只给出工程&#xff0c;等有时间再添加详细说明 现象 这是从之前的一个51单片机的程序移植过来的&#xff0c;主要修改了IIC启动和停止&#xff0c;以及数据发送的代码&#xff0c;我现在还不是很满意的一点是发送过程中要等待上一个字节发送完才能…

如何通过OpenHarmony的音频模块实现录音变速功能?

简介 OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;是由开放原子开源基金会孵化及运营的开源项目&#xff0c;是面向全场景、全连接、全智能时代的智能物联网操作系统。 多媒体子系统是OpenHarmony系统中的核心子系统&#xff0c;为系统提供了相机、…

hpc中查看显存占用,等效nvidia-smi

nvidia-smi在hpc中无法使用&#xff0c; 但是可以通过以下方法查看应用程序占用的显存 先执行程序&#xff0c;之后 bjobs输出 可以看到使用的是gpu01节点 之后 ssh gpu01

高刚性滚柱直线导轨有哪些优势?

滚柱导轨是机械传动系统中用于支持和引导滑块或导轨的装置&#xff0c;承载能力较高、刚性强及高精度等特点。特别适用于大负载和高刚性的工业设备&#xff0c;如机床、数控机床等设备&#xff0c;这些优势使其在工业生产和机械设备中得到了广泛的应用。 1、高精度&#xff1a;…

营收净利双降、股东减持,大降价也救不了良品铺子

号称“高端零食第一股”的良品铺子(603719.SH)&#xff0c;正遭遇部分股东的“用脚投票”。 5月17日晚间&#xff0c;良品铺子连发两份减持公告&#xff0c;其控股股东宁波汉意创业投资合伙企业、持股5%以上股东达永有限公司&#xff0c;两者均计划减持。 其中&#xff0c;宁…

切换python和python3的版本

参考&#xff1a;http://t.csdnimg.cn/iUtSR 进入root sudo su 使用 sudo 权限运行 update-alternatives 命令&#xff0c;为 python 和 python3 设置默认版本。 sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 sudo update-alternatives…

【Oracle篇】rman工具实用指南:常用命令详解与实践(第二篇,总共八篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

day 38 435.无重叠区间 763.划分字母区间 56. 合并区间 738.单调递增的数字 968.监控二叉树

435.无重叠区间 思路 为了使区间尽可能的重叠所以排序来使区间尽量的重叠&#xff0c;使用左边界排序来统计重叠区间的个数与452. 用最少数量的箭引爆气球恰好相反。 代码 class Solution {public int eraseOverlapIntervals(int[][] intervals) {Arrays.sort(intervals,(a,…

Python-温故知新

1快速打开.ipynb文件 安装好anaconda后&#xff0c;在需要打开notebook的文件夹中&#xff0c; shift键右键——打开powershell窗口——输入jupyter notebook 即可在该文件夹中打开notebook的页面&#xff1a; 2 快速查看函数用法 光标放在函数上——shift键tab 3...

JavaWeb Sevelet学习 创建Sevelet程序

Servlet 是JavaWeb中的开发动态Web一门技术 是由Sun公司提供的一个接口&#xff0c;允许开发者编写运行在服务器&#xff08;Tomcat&#xff09;上的Java程序&#xff0c;这些程序可以 生成动态网页内容&#xff0c; 响应客户端的请求。简单来说&#xff0c;Servlet就是Java E…

C++入门 基于ros的话题通信

一、 开发环境 ubuntu20.04 ros版本noetic 参考视频 https://www.bilibili.com/video/BV1Ci4y1L7ZZ/?p52&spm_id_from333.1007.top_right_bar_window_history.content.click&vd_source4cd1b6f268e2a29a11bea5d2568836ee 二、 创建两个功能包 //创建工作空间 工作空…

Aiseesoft Video Converter Ultimate视频转换大师,免安装中文旗舰版 v10.8.32

软件介绍 视频转换大师是一款集转码、编辑以及压缩功能于一身的专业软件&#xff0c;支持处理超过1,000种视频和音频格式。该工具不仅提供基础的格式转换服务&#xff0c;还拓展至高级功能&#xff0c;包括视频效果调整、数据压缩以及ID3信息编辑等&#xff0c;同时&#xff0…

socket地址理解

socket介绍 套接字的基本概念 1. 套接字的定义&#xff1a; 套接字&#xff08;socket&#xff09;是计算机网络中用于通信的端点&#xff0c;它抽象了不同主机上应用进程之间双向通信的机制。 2. 套接字的作用&#xff1a; 套接字连接应用进程与网络协议栈&#xff0c;使…

加密与解密(第四版)】第二十五章笔记

第二十五章 数据取证技术 25.1 硬盘数据的获取和固定 取证专用的Linux可启动光盘 硬盘复制机 利用取证计算机复制硬盘 手机&#xff08;JTAG&#xff09; 电子数据的固定&#xff08;HASH值&#xff09; 25.2 硬盘的分区和数据恢复 25.3 内存分析 25.4 动态仿真技术 25.…

虚拟ECU:彻底改变汽车软件开发与测试

汽车开发领域有着垂直性较强的一系列需求&#xff0c;其中最为瞩目的需求之一就是对安全高效的软件测试方法的需求。传统的汽车开发偏向使用硬件原型与真实ECU进行软件测试&#xff0c;但由于硬件设备往往在开发周期的中后阶段才生产完成&#xff0c;给汽车开发带来了成本与时间…

做OZON怎么选择物流,OZON物流Xingyuan

随着跨境电商的蓬勃发展&#xff0c;OZON作为俄罗斯领先的电商平台&#xff0c;吸引了大量中国卖家入驻。然而&#xff0c;物流作为跨境电商的关键环节&#xff0c;其选择对于卖家来说至关重要。本文将围绕“做OZON怎么选择物流”这一问题&#xff0c;深度解析OZON物流Xingyuan…

二分查找

题目链接 题目: 分析: 如果按照从头到尾的顺序一次比较, 每次只能舍弃一个元素, 效率是非常低的, 而且没有用到题目的要求, 数组是有序的因为数组是有序的, 所以如果我们随便找到一个位置, 和目标元素进行比较, 如果大于目标元素, 说明该位置的右侧元素都比目标元素大, 都可…

内网穿透--Frp-简易型(速成)-上线

免责声明:本文仅做技术交流与学习... 目录 frp项目介绍: 一图通解: ​编辑 1-下载frp 2-服务端(server)开启frp口 3-kali客户端(client)连接frp服务器 4-kali生成马子 5-kali监听 6-马子执行-->成功上线 frp项目介绍: GitHub - fatedier/frp: A fast reverse proxy…

什么是智慧校园信息平台?

智慧校园信息渠道是以物联网、云核算、大数据分析等新技术为核心技术&#xff0c;为校园供给一种才智型、数据化、网络化、协作型一体化的教育、科研、办理和生活服务的新式办理模式。那么一般的智慧校园信息渠道主要有哪些特色呢&#xff1f; 不同品牌的智慧校园信息渠道&…