目录
1.代码现象&问题
- 代码正常,log.txt文件被分配文件描述符fd为3。
- 关闭fd为0,log.txt文件被分配文件描述符fd为0。
- 关闭fd为2,log.txt文件被分配文件描述符fd为2。
- 关闭fd为1,什么都没有打印显示。
1.1关闭fd为0
1.2关闭fd为2
1.3关闭fd为1
2.文件描述符的分配规则
针对0/2的现象❓
- 文件描述符的分配规则:进程在分配 文件描述符的时候 会查询文件描述符表(内核的文件指针数组)。选择分配最小的没有被使用的文件描述符fd(遍历数组)。
针对1的现象❓1怎么不显示呢❓
- 依旧遵循上面的分配规则。
- printf是向stdout打印,stdout里面封装了fd为1。根据文件描述符分配规则,1号文件苗阜已经被分配给了log.txt。所以printf此刻向log.txt打印。
3.重定向
3.1现象
系统调用:man 3 write☞直接向1号文件写入
C语言:man 3 printf☞向显示器文件stdout写入☞FLIE类型☞封装的1号文件描述符
无论是printf/fprintf打印都是向stdout打印。(是C语言的库函数只认stdout(fd为1))
FLIE*->stdout->1
本来应该向显示器打印的数据,向文件打印了,这是什么技术❓
3.2解释
- 重定向技术:默认往显示器上打印,却打印进了指定的文件。
- printf和fprintf打印都只认识stdout,是C语言的库函数,只认stdout。
- stdout所封装的的文件描述符数字fd为1。
- 根据文件描述符表。首先关闭close(1),再创建打开log.txt文件。明确知道log.txt文件的文件描述符fd为1。在内核文件描述符表中1号下标中的元素指向☞log.txt文件了。
- printf和fprintf往1号文件打印。也就是往log.txt文件打印。
所谓重定向:改变文件进程的文件描述符表元素(改变指针也就改变指向)
4.缓冲区
4.1现象
去掉fflush刷新,发现log.txt虽然被创建出来了,但是什么内容都没有被写入❓
4.2解释
- 在C语言层面上struct FILE结构体里面不仅仅封装了文件描述符fd(_fileno)还存在语言级别的文件缓冲区。
- stdin/stdout/stderr都是一个结构体,都存在各自的语言级别的缓存。
- ❌使用printf/fprintf并不是直接通过向stdout封装的1号文件描述符向内核级缓存写入。
- ✔而是通过stdout的语言级别的缓冲区中。
- C语言把stdout的语言级的缓冲区的内容 通过1号文件描述符 刷新到对应的内核级缓存中
- fflush(stdout)传参是stdout。是因为是把用户级缓冲区 通过文件描述符拷贝到(刷新)内核级缓冲区,而不是把内核级缓冲区刷新到外设(这是OS定时刷新不管)
- 正常情况下,不加fflush,进程结束return的时候,会自动冲刷。
- 所以:因为在return进程结束自动冲刷之前,1号文件已经被close关闭了。数据还未来得及冲刷到内核级缓存中,文件已经被关闭,数据丢失了。
- 手动刷新:加上fflush或者 自动刷新:不关闭底层的1号文件