1.文件描述符fd
文件描述符:实际上就是内核中一个进程打开的文件描述信息数组(file* fd_array[])的下标,通过这个下标就能找到要操作的文件的描述信息,进而就可访问文件。
Linux进程默认打开的三个文件描述符:标准输入0、标准输出1、标准错误2.
因此文件描述符fd=0就表示标准输入,fd=1表示 标准输出,fd=2表示标准错误。
文件描述符的分配规则:在files_struct数组中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。由于0、1、2描述符已经被使用,所以再输出至少是3,除非0、1、2中有关闭的才会小于3.
2.重定向
重定向原理:通过改变文件描述符这个下标对应的文件描述信息,进而改变了要操作的文件,实现了数据流向的改变。
重定向实现接口函数(dup2):int dup2(int oldfd, int newfd);意思是说newfd是oldfd的一份拷贝,也就是说让newfd也指向了oldfd文件。比如让标准输出文件输出到指定test.txt文件中:int fd=open("./test.txt",O_RDWR),dup2(fd,1)。
追加重定向(>>):保持文件原内容不变,将新数据追加到文件末尾。
清空重定向(>):清空文件原有的内容,将新数据写入文件中。
3.文件流指针:FILE*
库函数都有:fopen、fwrite、fread、fclose、fseek,printf、fprintf、fgets…等
系统调用接口:open、write、read、close、lseek
库函数和系统调用接口的关系:库函数是对系统调用接口的封装,其实现了更多特定功能场景的复杂接口,但是库函数最终要实现功能还是要借助系统调用接口来实现。两者之间的区别是:库函数会自带缓冲区,等到程序退出或刷新缓冲区时才统一输出或写入文件;而系统调用没有带缓冲区。
文件流指针:FILE* ----对应库函数
文件描述符:int ----对应系统调用接口
文件流指针是一个结构体(fille_struct),其中内部有一个成员变量就是文件描述符。当我们通过库函数操作文件流指针,最终会演变为通过系统调用操作描述符。
文件流指针和文件描述符关系:文件流指针是个结构体,其封装了文件描述符。
4.动态库和静态库
gcc/g++的链接方式:动态链接、静态链接—默认方式是动态链接。
动态链接:链接动态库,只在生成可执行程序时记录文件的函数符号信息表,并没有把代码实现写入可执行程序中,因此程序运行时需要依赖动态库的存在,并且将动态库也要加载到内存中,好处是多个进程用到相同的库函数,则可以在内存中使用同一份库函数。
静态链接:链接静态库,在生成可执行程序时,直接将使用到的库函数的实现拿出来写入到可执行程序中,因此生成的可执行程序较大,但是运行的时候不需要依赖静态库的存在。
动态库的优点:共享、代码冗余小,便于模块代码替换,当一些模块化,便于功能替换的一些借口则使用动态库。
静态库的优点:依赖性低,当功能改动性小,并且只有当前程序使用的时候使用静态库。
动态库(.so)的生成:gcc --shared testlib.o… -o libtestlib.so
静态库(.a)的生成:ar -cr libtestlib.a testlib.o…