以上都是库函数,而库函数都是对系统调用接口的封装,让接口更好用。
系统调用接口:open,write,read,close,lsee
open 接口
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
库函数是对系统调用接口的封装,printf将数据写入显示器文件,但不仅仅是写入,还包含了数据格式化(将多个数据按照指定格式组织成为一个字符串再写入) 库函数fopen,fwrite,fread,fclose都是对系统接口open,write,read,close,lsee接口的封装。
向文件写入数据,数据不会立即被写入文件,而是先写入缓冲区,等刷新缓冲区的时候写入文件。对系统调用接口来说,本质上是没有这个缓冲区的。所以write向显示器写入数据是直接打印,而printf,fprintf,fwrite是刷新缓冲区的时候才打印。最基础的文件流结构指针对文件描述符做的改进:添加了缓冲区。
文件描述符:被打开的文件的操作句柄--是一个非负整数
1.当我们打开了一个文件,涉及到对应设备的操作
2.用一个结构体将这个设备描述起来(磁盘文件。就是描述操作是那一块硬盘的多少数据。以及 权限)一个进程可能会打开很多文件,这些文件信息就需要组织起来(本质上使用一个数组)
重定向的本质:
就是将一个描述符所对应位置的文件描述信息,给替换成另一个文件的描述,这就实现了在不做其他逻辑改变的情况下,改变了所操作的文件。
动态库与静态库的生成与使用: 库文件:将已经实现的代码进行打包,并不是为了生成可执行程序,而是为了给其他人提供接口使用 动态库:以位置无关代码打包
动态链接:生成可执行程序的时候,链接动态库,记录库中的符号表,生成的程序小,并且多个程序运行时在内存可以共享使用同一个动态库,运行更依赖动态库的存在,因为是运行程序的时候才会将动态库加载到内存中。
静态链接:生成可执行程序的时候,链接静态库,直接将库中所用到的函数的实现,拿到可执行程序中,不存在运行依赖,效率较高,但生成的可执行程序比较大,如果运行了多个用到同一个静态库的程序,则有可能库中代码在内存中有多份冗余。
生成库:把大量已经实现的代码打包起来
1.先把所有的源码进行编译汇编生成各自的二进制指令 gcc child.c -o child.o
2.将所有的生成的二进制文件给打包到一起 linux下的动态库命名:以Lib为前缀,以.so为后缀,中间是库名。
动态库:gcc --shared child.o -o libmychild.so gcc -fPIC -c child.c -o child.o gcc --shared child.o -o libmychild.so -fPIC:告诉编译器,在编译生成指令的时候产生与位置无关的代码(变量指令的地址都是相对偏移量) -c:只进行预处理,编译,汇编结束后退出 --shared:告诉编译器,生成的是一个库文件,而不是可执行程序
静态库:linux下的动态库命名:以Lib为前缀,以.a为后缀。 ar -cr gcc -c child.c -o child.o ar -cr libmychild.a child.0
使用库:使用-l来告诉编译器要使用那个库 gcc main.c -o main -lmychild 但是会报错,因为编译器回到系统指定目录下(/user/lib64)查找这个库
方法: 1:将库文件放到指定路径下:64位系统-/user/lib64 32位系统 -/user/lib 2:设置环境变量:export LIBRARY_PATH=${LIBRARY_PATH}:./将库文件所在目录添加在环境变量中。export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:./ 添加运行加载库文件的路径 3.使用gcc -L选择,指定库文件所在路径:gcc main.c -o main -L./-lmychild