7.GDB与文件IO

2023-10-29

1.GDB

什么是 GDB 调试

image-20211209081725297

1.1 GDB 准备工作

gdb 是一个 shell 指令,必须带有 -g 的参数,程序才将调试信息添加到文件中

g++ -g a.cpp -o a.out // 先为文件添加调试信息

打开所有的 warning 选项

g++ -g -Wall main.cpp -o main

如果文件与文件之间有引用如何编译:

g++ -g 1.cpp 2.cpp -o main 

开始调试

gdb a.out // gdb + 可执行程序

-g 的作用是在可执行文件中加入源码信息,比如可执行文件中第几条机器指令对应源码的第几行,但并不是把整个源文件都嵌入到可执行文件中,所以在调试时必须保证 gdb 可以找到源文件

给 main 函数设置参数值

set args 10000

image-20211101215845662

(1)查看相关指令

help 命令简写 

(2)继续执行上一条指令

<CR> // 回车操作

(3)查看代码信息

l +number// 默认从 number 行开始显示代码

1.2 GDB 设置断点

image-20211101222332949

常用指令:

b 行号 // 在某一行打断点
i b //查看自己打的断点å

(1)设置断点

b +number 

image-20211209093915141

address 显示的是打断点的地址

(2) 查看断点:

br l
image-20211209094553089

(3)删除断点:

br del +number // number 是断点编号,不是行号
image-20211209094928751

pending 状态的 breakpoint :

pending 的状态的指令都是我用 gdb 指令在 lldb 中运行报的错。pending 状态的信息是被挂起来的,没有被创建的 breakpoint ,这个指令并没有添加到 streamed 中

lldb 中的 pending 状态

(4)设置条件断点:

b +number if i=3 

1.3 GDB 运行程序

进入到 gdb 调试窗口后输入以下指令

image-20211101222917923

常用指令:

(1)从断点处运行一个程序

r or run 

(2)下一步

执行下一行代码,不跳入方法

n or next 

执行下一行diamante,跳入方法

s or step

一直执行,直到下一个断点停下来:

c or continue

(3)跳出

finish

2.文件 IO

2.1 相关定义

2.2.1 Linu

image-20211102101951357

2.2 虚拟地址空间

虚拟地址空间会被 CPU 中的 MMU 内存管理单元映射到真实地址内存中

2.2.1 为什么会有虚拟地址空间

1.内存空间剩余大小无法满足程序大小

2.内存空间不连续导致程序无法按序存放

2.2.2 虚拟地址空间

虚拟内存空间是系统为进程开辟的一段专门用来存地址的空间 ,大小为 0~4G

虚拟地址空间

image-20211102105509384

0~3G 用户区:用户可以自己操作 ,存放用户自己写的程序

受保护地址:用于保存空指针地址 Null ,nullptr

代码段:代码数据,二进制数据

堆:new 出来的对象都是在堆中存储。由低地址向高地址存储

共享库:库文件

栈:用于保存中间变量,由高地址向低地址存储

3G~4G 内核区

不允许用户自己调用,既没有读权限也没有写权限

如果想要调用就要使用“系统调用”的方法,调用系统 API

2.3 文件描述符

定义:文件描述符用于定位文件位置

2.3.1 程序和进程的区别

程序:不占用内存空间,只占用磁盘空间

进程:正在运行的一个程序,真正被内存分配资源的东西,一个进程启动之后会占用虚拟地址空间

2.3.2 如何找到文件

假设现在有一个程序 test.c 他的功能是向 a.txt 文件写东西,那么 test.c 是如何找到 a.txt 的

调用 fopen 函数会返回一个 file 文件指针,这个指针就是指向该进程的文件描述符表。文件描述符表是保存在 PCB 中的,文件描述符是一个数组,这个数组中包含当前进程所控制的所有文件,这个数组的大小为 1024

文件描述符表中前三个值是,标准输入,标准输出,标准错误文件的描述符

image-20211103102230978

上面对应的三个绿色 item 分别是标准输入,标准输出,标准错误。代表我们文件所进行的所有输入输出操作都是基于终端的

2.4 文件操作函数

下面是 Linux 系统中的相关函数

image-20211103115723626

2.4.1 如何查看系统手册

man 2 open // 找到 linux 系统 open 函数说明

image-20211103105344690

image-20211103104129812

2.4.2 如何使用 open 函数

文件保存在 lesson 09 中

1.将用的包进行调用

从上图可以看到,要想使用 open 函数必须先要调用对应的库函数

#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>

2.使用 perror 打印错误信息

在 open 函数当中会有一个 RETURN VALUE 的值,也就是这个函数的返回值。可以看到如果返回 -1 就说明没有找到文件描述符。这里可以使用 perror 打印错误,也就是出现 -1 的时候将具体的错误进行打印

image-20211103120458366

下图是 perror 的使用说明

image-20211103112204860

3.使用 gcc 编译程序

最后可以看到输出 open: 找不到文件的错误

image-20211103111956680

4.相关函数的解释说明

image-20211103112519619

5.完整代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include<unistd.h>
#include <stdio.h>

int main(){
        int fd = open("a.text",O_RDONLY);
        if(fd==-1){
                perror("open"); // 打印错误信息
        }
        close(fd);

        return 0;
}

6.可以传入多个占位符的参数

flags 参数是一个 int 类型的数据,它是占用 4 个字节,是 32 位 ,这个参数是可以传入多个占位符的。第一个是打开模式,第二个是文件的状态。占位符与占位符之间使用 | 隔开

image-20211103114537321

为什么使用 | 分开:

1.一个占位符代表一个 32 位的值,代表文件的读写模式,假设不同的模式由下面的二进制位表示

0_RDWR :

image-20211103114940554

0_CREAT:

image-20211103115051819

2.使用 | 可以将不同的模式进行累加

最后执行的是累加这个结果的指令

累加结果为:

image-20211103115124913
int fd = open("b.text",O_RDWR | O_CREAT,0777);

2.4.3 read 和 write 函数

文件保存在 lesson 10 中

1.函数描述

image-20211103120955841 image-20211103121019847 image-20211103121147529 image-20211103121243807

2.具体书写参数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <unistd.h>

int main(){
    // 1. 打开一个文件
    int srcfb = open("source.text",O_RDONLY);
    if(srcfb==-1){
        perror("open");
        return -1;
    }
    int tarfb = open("target.text",O_WRONLY|O_CREAT,0664);
    if(tarfb==-1){
        perror("open");
        return -1;
    }
    // 2. 频繁的读写操作
    char buf[1024] = {0}; // 定义一个缓冲区
    int len = 0; // 用于保存读取的字符
    while((len=read(srcfb,buf,sizeof(buf)))>0){
        write(tarfb,buf,len); // 写函数
    }
    // 3. 关闭文件
    close(srcfb);
    close(tarfb);

    return 0;
}

2.4.4 lseek 函数

1.lseek API 解析

这个函数是移动文件开始指针的

image-20211104123707518 image-20211104124032994 image-20211104124054127

**2.Demo **

在当前 .text 文件基础上,将文件下一此开始的指针向后移动 100 个字符

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
int main(){
  int fd = open("hello.text",O_RDWR);
  if(fd==-1){
    perror("open");
    return -1;
  }
  // 扩展文件长度
  int res = lseek(fd,100,SEEK_END);
  // 写入一个空字节,指针开始在后面的第 100 个指针之后
  write(fd," ",1);
  // 关闭文件
  close(fd);
  if(res==-1){
    perror("lseek") ;
    return -1;
  }
  close(fd);
  return 0;
}

在没有执行 lseek 这个执行文件之前 hello.text 是 65 个字节

image-20211104123435707

在执行这个文件之后变成了 166 个字节

image-20211104123552925

最后文件后面加了很多乱七八糟的东西

image-20211104124413224

2.4.5 stat 函数

1.API

image-20211105104906868

2.使用 linux 命令行调用

image-20211105094152594

3.stat 中传入的结构体类型

在 stat 函数 API 中有说明这个 struct stat 是做什么的:

需要创建一个空的结构体变量,stat 函数会自动对这个结构体变量赋值

image-20211105095703075

4.linux 中文件权限如何定义

文件权限是一个文件的属性,在上图中使用变量 st_mode 进行保存,这个是一个 16 位的存储单元。其中三位是 Other ,Group ,User 对文件的使用权限,特殊权限位不知道是什么,高地址存放文件类型

image-20211105100513972

① Linux 中如何定义文件权限

r—4

w—2

x—1

chmod 文件权限 文件名

Linux 文件权限如何书写

②Linux 如何表示文件类型与文件权限

上图所示,Linux 有 7 中文件类型(最后一个是掩码)

假设是一个套接字文件,他的十进制是 14 ,对应的2进制就是 1100 ,正好放在那四维上

image-20211105101820187

如何输出文件类型,将 st_mode 与 S_IFMT 进行 & 操作,其中 S_IFMT 是一个宏值,进行 & 操作后会得到一个值

image-20211105102452171

然后再对这个宏进行 swith 的判断,然后打印相关文件类型

image-20211105102536768

d,- ,l 都是什么文件类型

d:目录

-: 普通文件

l:连接文件

**5.Demo **

使用 C 语言代码输出查看某个文件的属性

#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>

int main(){
        struct stat statbuf; // 定义一个机构体变量
        int res  = stat("hello.text",&statbuf);
        if(res==-1){
                perror("stat");
                return -1;
        }
        printf("size:%ld\n",statbuf.st_size);// 调用结构体变量的属性
        return 0;

}

2.4.6 lstat 函数

1.API

image-20211105104944859

2.创建一个软连接

ln -s 软连接文件名 原文件名

可以看到软连接的大小是 9 但是 hello 源文件的大小是 166

image-20211105104448731

2.4.7 access 文件属性–是否有某个权限,是否存在

下面三个函数的文件在 lesson14 中

下图是改文件夹下的文件树,主要是上面文件进行改进

image-20211105141730424

1.API

image-20211105133501590

2.C 代码实现

判断一个文件是否存在

#include<unistd.h>>
#include<stdio.h>
int main(){
    int ret = access("a.txt",F_OK);
    if(ret==-1){
        perror("access");
    }
    printf("文件存在~~");
    return 0;
}

3.效果演示

image-20211105141859896

2.4.8 chmod 文件属性–修改用户权限

1.API

image-20211105134136943

2.C 代码实现

更改文件访问权限

#include<sys/stat.h>
#include<stdio.h>
int main(){
    int ret = chmod("a.txt",0777);
    if(ret==-1){
        perror("chmod");
        return -1;
    }
    return 0;
}

3.代码效果

image-20211105142118916

2.4.9 chmod 文件属性-- 更改文件所属用户和所属组

**1.查看当前系统的用户和组 **

vim /etc/passed

当前用户在后面的位置

image-20211105135056716

用同样的方法可以看到组的信息

vim /etc/group

当前我的用户是在组 id 1000 当中的

image-20211105135407700

创建一个 user 判断这个 user 所在组和组 id

sudo useradd gaogao // 创建高高这个用户
id gaogao // 将 gaogao 这个用户的相关 id 信息进行打印

在下图中分别是用户的id 信息,组 id ,组名称

image-20211105135704569

2.4.10 truncate文件属性-- 缩减或扩展文件尺寸

1.API

最终文件的尺寸会变成参数中所定义的尺寸大小

image-20211105140419472

2.C 代码实现

#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>
int main(){
    int ret = truncate("b.txt",20);
    if(ret==-1){
        perror("truncate");
        return -1;
    }
    return 0;
}

3.实现效果

通过上面对文件打印可以看到原先的 b.txt 中有 16 个字符(15+1 \0),下面将其扩展为 20 字符

image-20211105142420092

image-20211105142456300

2.5 Linux 复现 ls 文件属性操作

改文件保存在 lesson12 的 ls.c 中

2.5.1 main 带有参数的main 函数

调用接收两个参数的 main 函数,第一个参数是参数个数,第二个参数是参数列表的值。这样我们就可以接收到用户在命令行输入的参数了

带有参数的 main 函数使用

这里对参数个数进行判断:

因为 main 方法当中默认的一个参数是当前文件的名称,所以如果自己输入一个参数那么这个时候形参中保存的其实是有两个参数的,下面对参数输入个数进行判断

// 判断输入的参数是否正确
    if(argc < 2) {
        printf("%s filename\n", argv[0]);
        return -1;
    }

2.5.2 通过 stat 得到文件的相关信息

下面就要通过 stat 得到文件的相关信息,将这个信息赋值给一个 stat 类型的 struct

struct stat st; // 初始化用于赋值的结构体
    int ret = stat(argv[1], &st);
    if(ret == -1) {
        perror("stat");
        return -1;
    }

2.5.3 获取文件类型

我们得到 16 位的 st_mode 的值后就要进行 & 操作,将里面有用的信息进行解析和保存,将其保存到一个字符数组中

char perms[11] = {0};   // 用于保存文件类型和文件权限的字符串
    switch(st.st_mode & S_IFMT) { // 根据得到的宏值判断需要
        case S_IFLNK:
            perms[0] = 'l';
            break;
        case S_IFDIR:
            perms[0] = 'd';
            break;
        case S_IFREG:
            perms[0] = '-';
            break; 
        case S_IFBLK:
            perms[0] = 'b';
            break; 
        case S_IFCHR:
            perms[0] = 'c';
            break; 
        case S_IFSOCK:
            perms[0] = 's';
            break;
        case S_IFIFO:
            perms[0] = 'p';
            break;
        default:
            perms[0] = '?';
            break;
    }

2.5.4 获取文件权限

// 文件所有者
perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-'; // 这里进行有或者没有的一个判断
perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';

// 文件所在组
perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';

// 其他人
perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';

2.5.5 得到其他的文件属性

//5.硬连接数
int linkNum = st.st_nlink;

//6.文件所有者
char * fileUser = getpwuid(st.st_uid)->pw_name;

//6.文件所在组
char * fileGrp = getgrgid(st.st_gid)->gr_name;

//7.文件大小
long int fileSize = st.st_size;

//8.获取修改的时间
char * time = ctime(&st.st_mtime);
char mtime[512] = {0};
strncpy(mtime, time, strlen(time) - 1); // 将得到的指针结果赋值给一个 char 类型的数组

2.5.6 将以上的文件属性进行字符串拼接并打印

// 将输出结果进行字符串拼接
char buf[1024];
sprintf(buf, "%s %d %s %s %ld %s %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);
printf("%s\n", buf);

2.5.7 在 Linux 中使用该命令

1.将 .c 文件编译成可执行文件

gcc ls.c -o ls

2.执行 ls 指令

这里的 ls 指令因为是自己写的所以前面还是要加 ./ ,与此同时将 main 需要的参数拼接到文件名称之后

./ls hello.txt

3.最后的输出结果

上图是自己的输出结果,下图是系统的输出结果

image-20211105125017895

image-20211105125107047

其实,-l 和 hello.txt 应该都是 main 的两个参数

2.6 目录操作函数

目录和文件操作相同,因为目录就是一个个的文件

2.6.1 mkdir–创建目录

1.API

image-20211106094324340
#include<sys/stat.h>
#include<sys/types.h>
#include<stdio.h>

2.代码实现

int main(){
    int res = mkdir("aaa",0777); // 这里前面必须加 0 不加 0 就会调用一个10进制数
    if(res==-1){
        perror("mkdir");
        return -1;
    }
    return 0;
}

易错点:

在定义文件权限时需要在前面加一个 0 ,否则系统会认为是十进制数,导致权限操作失败

3.代码效果

image-20211106105344742

2.6.2 *getcwd , chdir --查看和修改进程目录

Demo 在 lesson14

1.API

image-20211106102025520
// 通用包
#include<stdio.h>
#include<unistd.h>
#include<string.h>
// open 函数相关
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>

2.代码实现

// 得到当前的工作目录
    char buf[128];
    (*getcwd)(buf,sizeof(buf)); // 得到当前进程目录,将其传给 buf 
    print("当前的工作目录是 %s",buf);

    // 更改当前的工作目录
    int res = chdir("/home/xu/C++/lesson13");
    if(res==-1){
        perror("chdir");
        return -1;
    }
    // 在当前修改的目录下创建文件
    int fd = open("lesson14.txt",O_CREAT,O_RDWR,0664);
    if(fd==-1){
        perror("open");
        return -1;
    }
    close(fd);

    // 在此打印当前工作目录
    char buf1[128];
    (*getcwd)(buf1,sizeof(buf1)); // 得到当前进程目录,将其传给 buf 
    print("当前的工作目录是 %s",buf);

3.代码演示

image-20211106110056943

image-20211106110110455

2.6.3 其他目录操作

image-20211106110227103

2.6.4 opendir,readdir,closedir–打开,读,关闭目录

image-20211106110403906

1.API

这里使用 man 3 opendir 查看

image-20211106111305481 image-20211106111104013 image-20211106111417414

其中 DIR 是一个 DIR 类型的成员变量,它有以下属性:

image-20211106114104869
#include<dirent.h>

2.代码

查看某个目录下的所有文件

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int getFileNum(const char * path);
// 读取某个目录下所有的普通文件的个数
int main(int argc, char * argv[]) {
    if(argc < 2) {
        printf("%s path\n", argv[0]);
        return -1;
    }

    int num = getFileNum(argv[1]);

    printf("普通文件的个数为:%d\n", num);

    return 0;
}
// 用于获取目录下所有普通文件的个数
int getFileNum(const char * path) {

    // 1.打开目录
    DIR * dir = opendir(path);

    if(dir == NULL) {
        perror("opendir");
        exit(0);
    }

    struct dirent *ptr;
    // 记录普通文件的个数
    int total = 0;
    while((ptr = readdir(dir)) != NULL) {

        // 获取名称
        char * dname = ptr->d_name;

        // 忽略掉. 和..
        if(strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {
            continue;
        }

        // 判断是否是普通文件还是目录
        if(ptr->d_type == DT_DIR) {
            // 目录,需要继续读取这个目录
            char newpath[256];
            sprintf(newpath, "%s/%s", path, dname);
            total += getFileNum(newpath);
        }

        if(ptr->d_type == DT_REG) {
            // 普通文件
            total++;
        }
    }

    // 关闭目录
    closedir(dir);

    return total;
}

3.代码演示

执行代码,并在代码后面拼接文件目录

image-20211106122852027

4.知识扩展

字符串的拼接操作:

int sprintf (char* buffer, const char* fmt, ...);
char newpath[256];
sprintf(newpath,"%s/%s",path,ptr->d_name);

字符串的比较操作

int strcmp ( const char * str1, const char * str2 );
strcmp(dname, ".");

2.6.5 dup 文件描述符的复制

1.API

image-20211106132253358

2.代码

使用 open 得到文件描述符 fd ,再使用 dup 得到文件描述符 fd1 。对 fd 关闭,然后再对 fd1 文件描述符写入

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main(){

    // 使用 open 的方法打开通配符
    int fd = open("a.txt",O_RDWR|O_CREAT,0664);
    // 复制得到的文件描述符
    int fd1 = dup(fd);

    if(fd1==-1){
        perror("dup");
        return -1;
    }
    // 判断 fd 和 fd1 之间是否相等
    printf("fd:%d,fd1:%d\n",fd,fd1);
    close(fd); // 关闭 fd 文件

    char* str = "Hello World";
    int ret = write(fd1,str,strlen(str)); // 判断仅适用赋值的描述符是否可以操作文件
    if(ret==-1){
        perror("write");
        return -1;
    }
    close(fd1);
    return 0;
}

3.代码演示

为什么进行 dup 复制的值和 fd 是不一样的。文件描述符类似于进程的 PCB ,进程 PCB 每打开一个文件就会创建一个文件 PCB ,这里暂且较为句柄,我们通过句柄去控制一个个的文件。每次去控制文件都会创建一个句柄。句柄的位置是从 3 开始的,并且使用 dup 的时候会每次从 pcb 的文件分配表中找到最小的可以存储句柄位置的地方保存这个句柄

所以 fd 和 fd1 的值是不一样的,但是他们都可以指向相同的文件

image-20211106162804020

2.6.6 dup2 文件描述符重定向

1.API

image-20211106140606860

2…代码

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main(){
    // 使用 open 的方法打开通配符
    int fd = open("1.txt",O_RDWR|O_CREAT,0664);
    // 复制得到的文件描述符
    if(fd==-1){
        perror("fd");
        return -1;
    }
    int fd1 = open("2.txt",O_RDWR|O_CREAT,0664);
    // 复制得到的文件描述符
    if(fd1==-1){
        perror("fd1");
        return -1;
    }
    printf("fd:%d,fd1:%d\n",fd,fd1);
    int fd2 = dup2(fd,fd1);
    // 判断 fd 和 fd1 之间是否相等
    printf("fd:%d,fd1:%d,fd2:%d\n",fd,fd1,fd2);

    char* str = "Hello World\n";
    int ret = write(fd1,str,strlen(str)); // 本来 fd1 指向 2.txt ,最后是向 1.txt 写入文件
    if(ret==-1){
        perror("write");
        return -1;
    }
    close(fd);
    close(fd1);
    return 0;
}

3.代码演示

打印每个文件描述符的指向

image-20211108095426278

将文件描述符进行重定位后 fd1 的文件指针指向了 1.txt,所以向 1.txt 写入

image-20211108095253729

2.txt 中则没有数据

image-20211108095501690

2.6.7 fcntl–文件控制函数

有点类似于前面所有函数的统一指令,对应文件 lesson17

**1.API **

在传参的地方有很多 … ,代表是这个函数中可以传入多个参数

image-20211108102006966
#include <unistd.h>
#include <fcntl.h>

阻塞与非阻塞:

描述的是函数调用的行为

阻塞:在进行耗时操作时进程或者现成被挂起,只有在得到结果之后才会返回

函数非阻塞:调用一个函数会立刻得到返回值,有时候会得到想要的结果,有时候不会。但不会阻塞当前进程

就像 Linux 的终端就是阻塞的,因为它在等待我们输入一个指令,但是在执行时又是不阻塞的

2.代码

#include <unistd.h>
#include <fcntl.h>
#include<stdio.h>
#include<string.h>

int main(){
    // 得到一个文件描述符后面对其操作
    int fd = open("1.txt",O_RDWR);
    // 得到文件描述符的状态的操作
    int flag = fcntl(fd,F_GETFL);
    // 在当前状态下添加追加操作,这里使用异或的方式代表追加
    flag|=O_APPEND;
    // 在上面状态基础上再写入一个操作
    int res = fcntl(fd,F_SETFL,flag);

    // 写入
    char* str = "\nnihao\n";
    write(fd,str,strlen(str));

    close(fd);

    return 0;
}

3.代码演示

可以看到原先 1.txt 的内容是 hello world

image-20211108104952177

在对文件进行相应的操作之后内容进行了追加

image-20211108105046026
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

7.GDB与文件IO 的相关文章

  • 仅使用containerd(不使用Docker)修剪容器镜像

    如果我刚刚containerd安装在 Linux 系统上 即 Docker 是not安装 如何删除未使用的容器映像以节省磁盘空间 Docker 就是这么方便docker system prune https docs docker com
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 如何使用 JSch 将多行命令输出存储到变量中

    所以 我有一段很好的代码 我很难理解 它允许我向我的服务器发送命令 并获得一行响应 该代码有效 但我想从服务器返回多行 主要类是 JSch jSch new JSch MyUserInfo ui new MyUserInfo String
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当

随机推荐

  • CentOS6系统中在/etc/rc.local添加开机自启动项启动失败

    CentOS6系统中在 etc rc local添加开机自启动项启动失败 应项目要求需要在开机的时候启动自己的Redis程序 想当然的直接就往 etc rc local当中添加启动命令 结果重启之后发现什么都没有发生 一开始还以为是配置的问
  • SQL增删改查语句学习

    删除语句 语法 DELETE FROM 表名 WHERE 条件 例如 DELETE FROM studentchose WHERE sc id 202046 DELETE FROM studentchose WHERE sc id 2020
  • 基于springboot的校园疫情防控系统【毕业设计,源码,论文】

    想要源码或其他毕设项目 可以私信 摘 要 随着信息技术和网络技术的飞速发展 人类已进入全新信息化时代 传统管理技术已无法高效 便捷地管理信息 为了迎合时代需求 优化管理效率 各种各样的管理系统应运而生 各行各业相继进入信息管理时代 校园疫情
  • Linux下远程git服务器拉取代码发布jar包脚本

    一 yum安装 在Linux上是有yum安装Git 非常简单 只需要一行命令 yum y install git 二 maven安装 参考https www jianshu com p 51e4e84e02cd 三 编写脚本 脚本步骤如下
  • Echarts 地图使用,以及tooltip轮播使用

    一 首先下载Echarts npm install echarts save 二 引入Echarts 全局引入main js中 echarts 4 0 import echarts from echarts Vue prototype ec
  • sql注入-union select

    什么是SQL注入 SQL注入 Sql Injection 是一种将SQL语句插入或添加到应用 用户 的输入参数中的攻击 这些参数传递给后台的SQL数据库服务器加以解析并执行 哪里存在SQL注入 GET POST HTTP头部注入 Cooki
  • 第一次使用Arduino IDE(mac os) 配置合宙ESP32C3(9.9包邮)且烧录代码的历程

    目录 Arduino 配置ESP32 1 Arduino 请更新至最新版 2 科学上网 3 添加开发板管理URL 配置 1 连接开发板 2 Arduino IDE 的配置 3 烧录代码 Arduino 配置ESP32 1 Arduino 请
  • java实现pdf上传、下载、在线预览、删除、修改等功能

    资源下载 pdf上传 下载 在线预览 删除 修改功能源码 最近闲来无事 做了一个pdf的小功能 以供各位大神参考 下面是效果展示图 功能主页 点击上传PDF按钮 上传文件之后 在线预览 开发环境 jdk 1 8 mysql 5 7 开发工具
  • 蓝牙 bluetooth-之一

    蓝牙profile的作用 蓝牙子系统应用程序的交互通过蓝牙profile实现 profile有些文献将其解释为子协议 似乎不是很准确 我依然以profile称呼它 蓝牙profile定义了蓝牙子系统分层结构中的每一层需要具有的功能和特性 G
  • loss.backward() Segmentation fault 段错误

    在运行一个非常简单的深度学习程序的时候 发现运行一段时间会报错 段错误 经过定位发现是执行loss backward 的时候出现的问题 而源码明显是没有什么问题的 具体排查可以这样 gdb args python train py 然后发现
  • CDI(Weld)基础<2> JSF+CDI+JPA项目示例

    2019独角兽企业重金招聘Python工程师标准 gt gt gt CDI可以理解为Spring 但其中的一些功能比spring更强大 灵活 本章是个简单的项目示例 推荐有一定基础的看 1 JPA定义 MVC M Entity public
  • dom型xss ---(waf绕过)

    目录 1 漏洞源码 2 进行绕过 2 1 使用老方法进行绕过 注入失败原因 2 2 分析注入方式 2 3 使用svg进行绕过 方式一 2 3 1 了解什么是dom树 以及dom树的构建 2 3 3 分析img方法失败的原因 可以在页面上添加
  • 二阶段提交java_分布式事务(一)两阶段提交及JTA

    分布式事务 分布式事务简介 分布式事务是指会涉及到操作多个数据库 或者提供事务语义的系统 如JMS 的事务 其实就是将对同一数据库事务的概念扩大到了对多个数据库的事务 目的是为了保证分布式系统中事务操作的原子性 分布式事务处理的关键是必须有
  • 【原生js实现】吃掉病毒,还森林一片祥和

    嗨 大家好 我是法医 一只治疗系前端码猿 与代码对话 倾听它们心底的呼声 期待着大家的点赞 与关注 游戏开始前 请容我感叹一声 掘金活动真多鸭 快卷不过来了 哈哈 其实最近也一直在加班 眼看游戏投稿时间快过去了 当初真想做个小游戏出来参加活
  • 基础编程练习 7-26 单词长度 (15 分)

    这个题的测试用例只卡在了空句子那一个 题目没有明确给出只有一个 的时候 什么也不输出直接结束 C include
  • sublime text中换行符替换成空(mac版)

    sublime text做字符串处理 需要将 xxx xxx xxx 改造为 xxx xxx xxx 1 alt command f 调用替换界面 2 shift command enter 在find what 输入 换行符 3 repl
  • Sqlite 嵌入式数据库移植和使用

    1 源代码的获取 sqlite是一个功能强大 体积小运算速度快的嵌入式数据库 采用了全C语言封装 并提供了八十多个命令接口 可移植性强 使用方便 下载地址 http sqlite org download html sqlite源代码 sq
  • 【Educoder python 作业答案】国防科技大学《大学计算机基础》Python入门-绘制炸弹轨迹 ※

    Educoder python 作业答案 国防科技大学 大学计算机基础 Python入门 绘制炸弹轨迹 第1关 绘制一个坐标点 第2关 绘制n个坐标点 第3关 绘制一条轨迹 第4关 更简单的绘制一条轨迹 第5关 绘制多条轨迹 第1关 绘制一
  • 接口传参时,不写字段,这种格式http://localhost:9000/findData/1 取参

    GetMapping findData id public List
  • 7.GDB与文件IO

    1 GDB 什么是 GDB 调试 1 1 GDB 准备工作 gdb 是一个 shell 指令 必须带有 g 的参数 程序才将调试信息添加到文件中 g g a cpp o a out 先为文件添加调试信息 打开所有的 warning 选项 g