Linux中的基础IO

news2024/11/16 11:37:59

目录

1、关于C语言中的文件操作符

1.1 C语言中写文件

1.2 C语言读文件

1.3 往显示器上输出信息

1.4 stdin & stdout & stderr

1.5 打开文件的方式

2、系统文件IO

2.1 写操作文件

2.2 读操作文件、

2.3 open

open函数的返回值

2.4 文件描述符

0 & 1 & 2

文件描述符的分配规则

2.5 重定向和dup2

 3、缓冲区相关

4、理解文件系统

4.1 inode

4.2 理解硬链接

4.3 软链接

5、动态库和静态库

静态库和动态库

a. 生成静态库

b. 生成动态库


1、关于C语言中的文件操作符

1.1 C语言中写文件

#include <stdio.h> 
#include <string.h>
int main() 
{
    FILE *fp = fopen("myfile", "w"); 
    if(!fp){
        printf("fopen error!\n"); 
    }
    const char *msg = "hello ltx!\n"; 
    int count = 5;
    while(count--){
        fwrite(msg, strlen(msg), 1, fp); 
    }
    fclose(fp); 
    return 0;
}

1.2 C语言读文件

#include <stdio.h> 
#include <string.h>
int main() 
{
    FILE *fp = fopen("myfile", "r"); 
    if(!fp){
        printf("fopen error!\n"); 
    }
    char buf[1024];
    const char *msg = "hello bit!\n";
    while(1){
        ssize_t s = fread(buf, 1, strlen(msg), fp);
        if(s > 0){ 
            buf[s] = 0; 
            printf("%s", buf); 
        }
        if(feof(fp)){ 
            break; 
        }
    }
    fclose(fp); 
    return 0; 
}

1.3 往显示器上输出信息

#include <stdio.h> 
#include <string.h>
int main() 
{
    const char *msg = "hello fwrite\n"; 
    fwrite(msg, strlen(msg), 1, stdout);
    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n"); 
    return 0;
}

1.4 stdin & stdout & stderr

C默认会打开三个输入输出流,分别是stdin, stdout, stderr

仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针

1.5 打开文件的方式

        r     Open text file for reading.
              The stream is positioned at the beginning of the file.

       r+    Open for reading and writing.
              The stream is positioned at the beginning of the file.

       w    Truncate(缩短) file to zero length or create text file for writing.
              The stream is positioned at the beginning of the file.

       w+   Open for reading and writing.                                                                                                       The file is created if it does not exist, otherwise it is truncated.
               The stream  is  positioned at the beginning of the file.

       a      Open for appending (writing at end of file).
              The file is created if it does not exist.
              The stream is positioned at the end of the file.

       a+   Open for reading and appending (writing at end of file).
              The file is created if it does not exist.  The initial file  position
              for reading is at the beginning of the file,
              but output is always appended to the end of the file.

以上就是C语言中的一些文件操作

2、系统文件IO

操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问,当然,其实其他语言在底层在一定程度上都可以说成时对系统操作的一些封装。

2.1 写操作文件

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <string.h>
int main() 
{
    umask(0);
    int fd = open("myfile", O_WRONLY|O_CREAT, 0644); 
    if(fd < 0){
        perror("open"); 
        return 1; 
    }
    int count = 5;
    const char *msg = "hello ltx!\n"; 
    int len = strlen(msg);
    while(count--){
        write(fd, msg, len);
        //fd: 文件操作符, msg:缓冲区首地址, len: 本次读取,期望写入多少个字节的数据。    
        //返回值:实际写了多少字节数据
    }
    close(fd); 
    return 0; 
}

2.2 读操作文件、

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <string.h>
int main() 
{
    int fd = open("myfile", O_RDONLY); 
    if(fd < 0){
        perror("open"); 
        return 1; 
    }
    char buf[1024];
    while(1){
        ssize_t s = read(fd, buf, strlen(msg));//类比write 
        if(s > 0){
            printf("%s", buf); 
        }else{
            break; 
        }
    }
    close(fd); 
    return 0; 
}

2.3 open

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

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

        pathname: 要打开或创建的目标文件

        flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。

参数:

        O_RDONLY: 只读打开

        O_WRONLY: 只写打开

        O_RDWR  : 读,写打开

上面这三个常量,必须指定一个且只能指定一个

        O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限

        O_APPEND: 追加写

返回值

        成功:新打开的文件描述符

        失败:-1

如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。

open函数的返回值

        open函数的返回值是一个叫做文件描述符的东西,这个东西具体是什么呢,下面咱们展开讲讲:

        首先,我们得知道两个概念:一个是库函数、另一个是系统调用。

        什么是库函数,我们刚刚使用的C语言文件操作的相关函数,就叫做库函数。

        什么是系统调用呢:系统调用,其实也简单,他本质也是一些函数,但是是操作系统提供的。因为呢在一个操作系统的底层,他需要和一些驱动硬件的驱动做交互,也就是管理整个系统,不管是硬件,还是一些硬件驱动的软件,那些层面的功能十分的繁杂繁琐,要是这样暴露给开发者,那样的话,开发的成本会大大提升,所以呢在设计之初呢,人们选择对操作系统的底层做封装,不暴露下层的细节,对上层提供可操作的接口,这些接口就是系统调用,用来和底层交互。这就是系统调用。
 

         了解万这些,我们再来看看open函数的返回值,

        既然open是操作系统对上层提供的一个系统调用,那么他的返回值,就一定和它内部的实现,也可以说是和操作系统对打开文件操作的实现有关系。接下来我们就说说操作系统是怎么对以打开文件做管理的:

        打开文件这个操作实际上就是将文件内容再加到内存,以便CPU进行操作,就是内存和磁盘的交互,文件从磁盘上被加载到内存,那操作系统是如何管理内存中的文件的呢?

        我们在之前的文章中提到过一个PCB,它本质上就是一个数据结构,用来管理内存中的进程的,那文件也是被某个进程打开的,是否也被他管理呢。是的,是这样的。

        用Linux做举例,Linux底层对PCB的实现,使用一个叫 task_struct 的结构体实现,在task_struct 这个结构体中,有一个叫 files 的结构体指针,指向一个 files 的结构体,这个 files 结构体中有一个指针数组,这些指针数组中的指针,用以指向一个个被打开的文件。这个指针数组中的下标,其实就是open函数的返回值,这样子说就很好理解了,而这个open函数的返回值,也就是指针数组的下标,就叫做文件描述符,

2.4 文件描述符

        接下来我们再详细分析一下这个文件描述符。

        通过上面的讲述,我们知道了,文件描述符就是一个数组的下标,也就是一个整数,那么我们打开第一个文件的时候,open的返回值是不是就是0呢,接着是1,2,3……我们来写代码验证一下,

#include <iostream>

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

using namespace std;

int main() {
    size_t fd1 = open("test01.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    size_t fd2 = open("test02.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    size_t fd3 = open("test03.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);

    cout << "fd1:" << fd1 << endl;
    cout << "fd2:" << fd2 << endl;
    cout << "fd3:" << fd3 << endl;

    close(fd1);
    close(fd2);
    close(fd3);

    return 0;
}

运行结果:

         这里显示运行结果和我们想的并不一样,这是为什么,为什么从3开始,那么0,1,2去哪里了,接下来我们看看:

        人们都说在Linux中,一切皆文件,从哪里体现,在这里就能窥探到一些,

        在一个进程创建的时候,操作系统就会默认把标准输入(对应键盘),标准输出(对应显示器),标准错误(对应显示器),这三个打开文件加载到 files_struct 这个结构体中,这三个分别会将文件描述符为0 ,1,2的三个位置占据,所以我们在创建文件的时候,就会从3这个位置开始分配文件描述符。

0 & 1 & 2

        Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0,  标准输出1,  标准错误2.

        0,1,2对应的物理设备一般是:键盘,显示器,显示器

所以输入输出还可以采用如下方式:

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <string.h>
int main() 
{
    char buf[1024];
    ssize_t s = read(0, buf, sizeof(buf)); 
    if(s > 0){
        buf[s] = 0;
        write(1, buf, strlen(buf)); 
        write(2, buf, strlen(buf)); 
    }
    return 0; 
}

        而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件

文件描述符的分配规则

        在一个进程启动的时候,文件描述符为0,1,2的三个位置已经被占了,如果我们将1或者0中对应的文件关闭,这个时候在打开文件,这个文件的文件描述符还会是3嘛,我们来验证一下:

#include <iostream>

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

using namespace std;

int main() {
    
    close(1);
    size_t fd1 = open("test01.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);

    cout << "fd1:" << fd1 << endl;
    
    close(fd1);
    return 0;
}

运行结果:

         我们发现这里啥也看不到,这是为啥,因为我们关掉了文件描述符为1的文件,正是标准输出,那我们,打开这个文件,看看里面有没有内容

         我们发现,原本该输出到命令行的内容,被写入到了这个文件中,而且显示,被打开的这个文件的文件描述符是1,而不是3,所以这里就说明了,文件描述符是从0开始,找到第一个空的,这样子进行分配的,

        细看上面这个例子,这不就是重定向嘛,哈哈哈哈,没错,其实linux使用 > 进行重定向底层的实现原理就和这个差不多,下面我们顺便看看重定向

2.5 重定向和dup2

        通过上面那个例子,我们发现本该输出到命令行上的内容,被写入到了test01.txt这个文件中了,这种现象就叫做重定向,

        上面那种实现,就是重定向的实现的一种,将系统的标准输出关闭,然后打开文件,使用系统打印函数,就可以将内容写入到文件中,

        另外呢,系统给我们提供了一个系统调用dup2,其实dup函数有好几个,但是最常用的就是dup2,

#include <unistd.h>
int dup2(int oldfd, int newfd);

注意:这里的oldfd和newfd各自所指的是什么,比如我们现在要将本该输出到命令行上的内容重定向到test01中,那么oldfd就是test01的文件描述符,newfd就是标准输出1,它的本质就是将oldfd中存储的指针,拷贝并覆盖newfd指针所在数组指针的位置,

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

using namespace std;

int main() {
    size_t fd = open("test01.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    dup2(fd, 1);
    cout << "hello ltx!" << endl;
    close(fd);
    return 0;
}

运行结果:

 3、缓冲区相关

我们看一段代码:

#include <stdio.h> 
#include <string.h>
int main() 
{
    const char *msg0="hello printf\n";
    const char *msg1="hello fwrite\n";
    const char *msg2="hello write\n";
    printf("%s", msg0);
    fwrite(msg1, strlen(msg0), 1, stdout); 
    write(1, msg2, strlen(msg2));
    fork(); 
    return 0;
}

运行结果:

//hello printf
//hello fwrite
//hello write

但如果对进程实现输出重定向呢?./hello > file  我们发现结果变成了:

//hello write
//hello printf
//hello fwrite
//hello printf
//hello fwrite

        我们发现printf和fwrite都输出了两次,write输出了一次,这是为什么?那肯定就和fork有关了,

        一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。printf和fwrite库函数会自带缓冲区库,当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后但是进程退出之后,会统一刷新,写入文件当中。但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。

write没有变化,说明没有所谓的缓冲。

4、理解文件系统

        我们使用ls -l的时候看到的除了看到文件名,还看到了文件元数据。

 每行包含7列:

        模式

        硬链接数

        文件所有者

        组

        大小

        最后修改时间

        文件名

ls -l读取存储在磁盘上的文件信息,然后显示出来

其实这个信息除了通过这种方式来读取,还有一个stat命令能够看到更多信息

 上面的执行结果有几个信息需要解释清楚

4.1 inode

为了能解释清楚inode我们先简单了解一下文件系统

         Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的,

        Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子

        超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了

        GDT,Group Descriptor Table:块组描述符,描述块组属性信息,有兴趣的同学可以在了解一下

        块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用

        inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。

        i节点表:存放文件属性  如  文件大小,所有者,最近修改时间等

        数据区:存放文件内容

创建一个新文件主要有一下4个操作:

1. 存储属性

        内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。

2. 存储数据

        该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推。

3. 记录分配情况

        文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。

4. 添加文件名到目录

        新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。

4.2 理解硬链接

我们看到,真正找到磁盘上文件的并不是文件名,而是inode。  其实在linux中可以让多个文件名对应于同一个inode。  

[root@localhost linux]# touch abc

[root@localhost linux]# ln abc def

[root@localhost linux]# ls -1i

abc def 263466 abc 263466 def

abc和def的链接状态完全相同,他们被称为指向文件的硬链接。内核记录了这个连接数,inode263466 的硬连接数为2。

我们在删除文件时干了两件事情:

        1.在目录中将对应的记录删除,

        2.将硬连接数-1,如果为0,则将对应的磁盘释放。

 

4.3 软链接

硬链接是通过inode引用另外一个文件,软链接是通过名字引用另外一个文件,在shell中的做法

 我们发现软链接的文件有自己的inode

5、动态库和静态库

静态库和动态库

        静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库

        动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

        一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码,在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)

        动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。

a. 生成静态库

[root@localhost linux]$ ls
add.c  add.h  main.c  sub.c  sub.h
[root@localhost linux]$ gcc -c add.c -o add.o 
[root@localhost linux]$ gcc -c sub.c -o sub.o
#生成静态库
[root@localhost linux]$ ar -rc libmymath.a add.o sub.o 
#ar是gnu归档工具,rc表示(replace and create)
#查看静态库中的目录列表
[root@localhost linux]$ ar -tv libmymath.a 
rw-r--r-- 0/0   1240 Sep 15 16:53 2017 add.o 
rw-r--r-- 0/0   1240 Sep 15 16:53 2017 sub.o 
#t:列出静态库中的文件
#v:verbose 详细信息
[root@localhost linux]$ gcc main.c -L. -lmymath 
#-L 指定库路径
#-l 指定库名
#测试目标文件生成后,静态库删掉,程序照样可以运行。

库搜索路径

        从左到右搜索-L指定的目录。

        由环境变量指定的目录  (LIBRARY_PATH)

        由系统指定的目录

                /usr/lib

                /usr/local/lib

b. 生成动态库

shared: 表示生成共享库格式

fPIC:产生位置无关码(position independent code)

库名规则:libxxx.so

[root@localhost linux]$ ls
add.c  add.h  main.c  sub.c  sub.h
[root@localhost linux]$ gcc -fPIC -c add.c -o add.o 
[root@localhost linux]$ gcc -fPIC -c sub.c -o sub.o
#生成动态库
[root@localhost linux]$ gcc -shared -o libmymath.so *.o 
[root@localhost linux]$ gcc main.c -L. -lmymath 
#-L 指定库路径
#-l 指定库名

但是生成动态库之后,运行不了,还是会报错,

        动态链接器,在它内部有一个默认的搜索顺序,按照优先级从高到低的顺序是:

        1.可执行文件内部的 DT_RPATH 段

        2.系统的环境变量 LD_LIBRARY_PATH

        3.系统动态库的缓存文件 /etc/ld.so.cache

        4.存储动态库 / 静态库的系统目录 /lib/, /usr/lib 等

        按照以上四个顺序,依次搜索,找到之后结束遍历,最终还是没找到的话,动态连接器就会提示动态库找不到的错误信息。

这个时候,就需要把我们的动态库的路径配置到环境变量中,或者配置到系统配置文件中,,通常我们的解决办法:

        1、拷贝.so文件到系统共享库路径下, 一般指/usr/lib

        2、更改:LD_LIBRARY_PATH

                export LD_LIBRARY_PATH = #$LD_LIBRARY_PATH + "路径"

        3、ldconfig  配置/etc/ld.so.conf.d/,ldconfig更新

                cat /etc/ld.so.conf.d/ltx.conf(在创建的这个文件中配置我们的动态库路径)

                        /root/tools/linux

                ldconfig(创建出动态装入程序(ld.so)所需的连接和缓存文件)

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

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

相关文章

MybatisPlus-插件篇

文章目录 一、前言二、插件1、分页插件2.1.1、引入依赖2.1.1、配置分页插件2.1.3、使用分页方法 2、乐观锁插件2.1、引入依赖2.2、添加版本字段2.3、配置乐观锁插件2.4、执行更新操作 三、总结 一、前言 本文将详细介绍mybatisplus中常用插件的使用。 二、插件 1、分页插件 …

双向A*算法

前面看最佳路径优先搜索算法的时候顺便研究了一下它的改进算法&#xff1a;双向最佳路径优先搜索算法。那既然有双向最佳路径优先搜索算法自然也可以有双向A* 算法。这篇文章简单看一下双向A*算法的基本原理以及代码实现。 基本原理 双向A* 算法是一种用于解决图搜索问题的启…

供水营业收费管理系统:智慧水务的得力助手

随着我国经济的快速发展&#xff0c;城市化进程不断加快&#xff0c;供水行业的需求也不断增长。为满足人们日益增长的用水需求&#xff0c;提高供水企业的管理水平和服务质量&#xff0c;供水营业收费管理系统应运而生&#xff0c;成为智慧水务的得力助手。 一、供水营业收费管…

算法通关村-----哈希和队列的基本知识

哈希概念 哈希也称为散列&#xff0c;就是把任意长度的输入&#xff0c;通过散列算法&#xff0c;变成固定长度的输出&#xff0c;这个输出值就是散列值。 哈希存储 现在有1&#xff0c;2&#xff0c;3…15&#xff0c;要将其存储到大小为7的哈希表中&#xff0c;应该如何存…

Android studio实现水平进度条

原文 ProgressBar 用于显示某个耗时操作完成的百分比的组件称为进度条。ProgressBar默认产生圆形进度条。 实现效果图&#xff1a; MainActivity import android.os.Bundle; import android.view.View; import android.app.Activity; import android.widget.Button; import…

算法 稀疏数组 数组优化 数组压缩 二维数组转稀疏数组 算法合集(二)

1. 五子棋游戏&#xff0c;玩家对战一半停战休息&#xff0c;此时需要存储当前对战双方棋子信息 a. 采用二维数组存储&#xff1a; 0为空&#xff0c; 1代表黑棋 2代表蓝色棋子 b. 棋盘为11行&#xff0c;11列 > int [][] chessArray new int [11][11]; c. 出现的问题&am…

RT_Thread内核机制学习(五)邮箱

之所以引入线程间通信&#xff0c;是为了实现互斥&#xff0c;休眠-唤醒。 队列可以指定消息的大小、个数&#xff0c;存放消息&#xff0c;取出消息时都是由rt_memcpy()实现。 邮箱 保存数据的核心在于数组&#xff0c;只能存放unsigned long类型数据&#xff0c;数据存取、…

Acwing798.差分矩阵

前缀和与差分 图文并茂 超详细整理&#xff08;全网最通俗易懂&#xff09;_前缀和差分_林小鹿的博客-CSDN博客 代码展示&#xff1a; #include<iostream> #include<cstdio> using namespace std; const int N 1e3 10; int a[N][N], b[N][N]; void insert(int x…

在iPhone 15发布之前,iPhone在智能手机出货量上占据主导地位,这对安卓来说是个坏消息

可以说这是一记重拳&#xff0c;但似乎没有一个有价值的竞争者能与苹果今年迄今为止的智能手机出货量相媲美。 事实上&#xff0c;根据Omdia智能手机型号市场跟踪机构收集的数据&#xff0c;苹果的iPhone占据了前四名。位居榜首的是iPhone 14 Pro Max&#xff0c;2023年上半年…

Python Qt学习(五)Checkbox

源码 # -*- coding: utf-8 -*-# Form implementation generated from reading ui file qt_checkbox.ui # # Created by: PyQt5 UI code generator 5.15.9 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this fil…

ATF(TF-A)安全通告 TFV-3 (CVE-2017-7563)

安全之安全(security)博客目录导读 ATF(TF-A)安全通告汇总 目录 一、ATF(TF-A)安全通告 TFV-3 (CVE-2017-7563) 二、CVE-2017-7563 一、ATF(TF-A)安全通告 TFV-3 (CVE-2017-7563) Title RO内存始终在AArch64 Secure EL1下可执行 CVE ID CVE-2017-7563 Date 06 Apr 2017 …

字符设备驱动框架解析

一、字符设备驱动框架解析 设备的操作函数如果比喻是桩的话&#xff08;性质类似于设备操作函数的函数&#xff0c;在一些场合被称为桩函数&#xff09;&#xff0c;则&#xff1a; 驱动实现设备操作函数 ----------- 做桩 insmod调用的init函数主要作用 --------- 钉桩 rm…

LinearAlgebraMIT_11_MatrixSpace/Rank==1‘sMatrix/SmallWorldGraph

x.1 矩阵空间 向量空间定义&#xff1a;满足加法和数乘的封闭性。就类似向量空间一样&#xff0c;也存在着矩阵空间的定义。举个例子&#xff0c;例如所有的3x3的矩阵构成的矩阵空间M&#xff0c;它的纬度就是9&#xff0c;如[1, 0, …], [0, 1, …]。对于M中所有对称矩阵组成…

Ansible学习笔记3

ansible模块&#xff1a; ansible是基于模块来工作的&#xff0c;本身没有批量部署的能力&#xff0c;真正具有批量部署的是ansible所运行的模块&#xff0c;ansible只是提供一个框架。 ansible支持的模块非常多&#xff0c;我们并不需要把每个模块记住&#xff0c;而只需要熟…

Ubuntu20以上高版本如何安装低版本GCC

安装了Ubuntu 20.04之后&#xff0c;通过命令行 sudo apt-get install build-essential安装gcc&#xff0c;再通过命令行 gcc -v可查看gcc版本为gcc13 如果想用低版本的gcc&#xff0c;比如gcc4.8&#xff0c;尝试输入命令 sudo apt-get install gcc-4.8会提示找不到gcc4.8的…

胡歌深夜发文:我对不起好多人

胡歌的微博又上了热搜。 8月29日01:18分&#xff0c;胡歌微博发文称&#xff1a;“我尽量保持冷静&#xff0c;我对不起好多人&#xff0c;我希望对得起这短暂的一生”&#xff0c;并配了一张自己胡子拉碴的图&#xff0c;右眼的伤疤清晰可见。 不少网友留言称“哥你又喝多了吗…

基于Java+SpringBoot+Vue前后端分离教师工作量管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

希尔排序(JAVA实例代码)

目录 希尔排序 一、概念及其介绍 二、适用说明 三、过程图示 四、Java 实例代码 ShellSort.java 文件代码&#xff1a; 希尔排序 一、概念及其介绍 希尔排序(Shell Sort)是插入排序的一种&#xff0c;它是针对直接插入排序算法的改进。 希尔排序又称缩小增量排序&#…

【2023年11月第四版教材】《第9章-范围管理》(第二部分)

《第9章-范围管理》&#xff08;第二部分&#xff09; 4 规划范围管理4.1 范围管理计划★★★ &#xff08;21下29&#xff09;4.2 需求管理计划★★★ &#xff08;22上27&#xff09; 5 收集需求5.1 数据收集★★★5.2 决策★★★5.3 数据表现★★★5.4 人际关系与团队技能★…

【pyqt5界面化开发-6】抽屉布局界面的开发

目录 0x01 前言&#xff1a; 一、封装的主窗口类 第一步&#xff1a;封装窗口类 第二步&#xff1a;添加抽屉界面 第三步&#xff1a;添加抽屉界面的相关布局 第四步&#xff1a;每一个抽屉界面的点击触发 二、封装的抽屉类 三、程序入口程序 四、完整代码 0x01 前言&…