Linux 用户缓冲区

news2024/12/23 13:41:39

1. 文件描述符的分配规则

我们知道Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入stdin--0, 标准输出stdout--1, 标准错误stderr--2。0,1,2对应的物理设备一般是:键盘,显示器,显示器.接下来我们来研究文件描述符的分配规则,代码如下。

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
        int fd = open("file.txt",O_CREAT|O_WRONLY);
        if(fd<0)
        {
                perror("open");
                return 1;
        }
        printf("fd: %d\n",fd);
        close(fd);
        return 0;
}

输出发现是 fd: 3 ,我们再关闭0或者2,在看看结果。

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
        close(0);
        int fd = open("file.txt",O_CREAT|O_WRONLY);
        if(fd<0)
        {
                perror("open");
                return 1;
        }
        printf("fd: %d\n",fd);
        close(fd);
        return 0;
}

发现是结果是: fd: 0 ,可见,文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

2. 重定向

那如果关闭1呢?看代码:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
        close(1);
        int fd = open("file.txt",O_CREAT|O_WRONLY);
        if(fd<0)
        {
                perror("open");
                return 1;
        }
        char * message="hello world\n";
        write(1,message,strlen(message));
        close(fd);
        return 0;
}

在这里我们先将1号文件关闭后再打开 file.txt 文件,之后向1号文件内写入字符串,编译运行之后来查看结果。

默认情况下1号文件是显示器,我们可以看到屏幕并没有打印字符串,很正常因为我们把屏幕关闭了,但它却把内容写到了file.txt内,这个现象就是输出重定向。

当我们把1号文件关闭后再创建了一个file.txt文件,该文件就会占据1号文件的位置,那么当我们向1号文件写入时,自然就写入到了file.txt里。

3. 使用 dup2 系统调用

显然对于先关闭再打开这样的操作还是很麻烦,其实只需要struct file* fd_array[ ]数组里对应下标的值拷贝一份放到目标下标里,就可以完成一次重定向。

dup2函数是Linux系统调用的一部分,用于复制文件描述符。它的原型定义在<unistd.h>头文件。

dup2函数的作用是将文件描述符oldfd复制到文件描述符newfd。如果newfd已经打开,它会先被关闭。如果newfd等于oldfd,则dup2返回newfd而不关闭它。dup2是一个原子操作,这意味着它要么完全成功,要么完全失败,不会出现部分成功的情况。

dup2函数在文件描述符的管理中非常有用,例如在重定向输入输出时。例如,可以使用dup2将标准输出(STDOUT_FILENO)重定向到一个网络套接字,或者将标准错误(STDERR_FILENO)重定向到一个文件。

如果dup2调用成功,它返回新的文件描述符;如果失败,则返回-1,并且errno会被设置以指示错误原因。

在实际编程中,dup2可以用来创建文件描述符的副本,或者在需要时关闭和重新打开文件描述符,以改变它们的行为或关联的文件。

示例代码如下

#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("file.txt",O_CREAT|O_WRONLY);
        if(fd<0)
        {
                perror("open");
                return 1;
        }
        //重定向
        dup2(fd,1);
        char * message="hello world\n";
        write(1,message,strlen(message));
        return 0;
}

4. 缓冲区

我们有以下代码,其中 printf 和 fwrite 均为库函数,而 write 为系统调用接口。

#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;
}

运行出结果:

如果对进程实现输出重定向,使用 ./test1 > file1.txt 命令, 我们发现结果变成了:

我们发现 printf 和 fwrite (库函数)都输出了2次,而 write 只输出了一次(系统调用)。肯定和 fork有关! 一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。 printf fwrite 库函数会自带缓冲区,当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。 而我们放在缓冲区中的数据,就不会被立即刷新,但是进程退出之后,会统一刷新,写入文件当中。 但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。 write 没有变化,说明没有所谓的缓冲。

综上: printf fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这里所说的缓冲区, 都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区。 那这个缓冲区谁提供呢? printf fwrite 是库函数, write 是系统调用,库函数在系统调用的“上层”, 是对系统 调用的“封装”,但是 write 没有缓冲区,而 printf fwrite 有,足以说明,该缓冲区是二次加上的,又因为是 C,所以由C标准库提供。

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

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

相关文章

字符串原始字面量

简介&#xff1a;C11中添加定义了原始字符串的字面量&#xff0c;定义方式为&#xff1a;R"xxx(原始字符串)xxx",其中&#xff08;&#xff09;两边的字符串可以省略。原始字面量R可以直接表示字符串的实际含义&#xff0c;而不需要额外对字符串做转译或链接等操作 …

ddpm和ddim小记

前面分析了DDPM和DDIM&#xff0c;但是仍然感觉对其理解不是和透彻&#xff0c;最近又学习了下&#xff0c;简单记录一下进一步的理解。为了方便理解&#xff0c;这里直接以两个像素的灰度图像为例。前面讲过无论是DDPM还是DDIM&#xff0c;他们的训练过程都是一样的&#xff0…

一套采用JAVA语言开发的数字化产科管理平台源码,自主知识产权,三甲综合医院应用案例,系统稳定运行,全套源码交付。

一套采用JAVA语言开发的一套数字化产科管理平台源码&#xff0c;自主知识产权&#xff0c;三甲综合医院应用案例&#xff0c;系统稳定运行。全套源码交付。 数字化产科管理平台源码技术栈&#xff1a; 技术架构&#xff1a;前后端分离 开发语言&#xff1a;Java 开发工具…

深度学习基础--梯度下降与初始化

在神经网络的背景下&#xff0c;它们用于寻找能够最小化损失函数的参数&#xff0c;使模型能够根据输入准确预测训练数据的输出。基本方法是随机选择一组初始参数&#xff0c;然后逐步进行微小调整&#xff0c;平均而言这些调整会降低损失。每一次的调整都是基于当前参数位置对…

ERROR: Cannot uninstall numpy 1.24.2, RECORD file not found.

目录 1.问题描述&#xff1a;2.解决方法&#xff1a;2.1流程2.2结果 小结&#xff1a; 1.问题描述&#xff1a; 卸载 numpy 时报错&#xff1a; ERROR: Cannot uninstall numpy 1.24.2, RECORD file not found. You might be able to recover from this via: pip install --f…

HTB-sequal(mysql)

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解sequal这台靶机 渗透过程 信息搜集 服务器开放了3306mysql端口思路&#xff1a;mysql爆破-sC参数会执行 相关的默认脚本 连接mysql数据库 通过空密码连接道mysql数据库flag&#xff1a;7b4bec00d1a39…

【GD32】从零开始学GD32单片机 | USB通用串行总线接口+HID键盘例程(GD32F470ZGT6)

1. 简介 USB&#xff0c;全称通用串行总线&#xff0c;相信大家都非常熟悉了&#xff0c;日常生活只要用到手机电脑都离不开这个接口&#xff0c;像鼠标键盘U盘都需要使用这个接口进行数据传输&#xff0c;下面简单介绍一下。 1.1 版本标准 USB的标准总体可以分为低速、全速和…

04:布局规划

1.切换到丝印层 2.用2D线对模块区域划分

keil5烧录后不自动复位和Flash Download failed - “Cotex-M3“报错解决

目录 项目场景&#xff1a; 复位问题描述 复位原因分析&#xff1a; 复位解决方案&#xff1a; 下载错误问题描述 下载错误原因分析&#xff1a; 下载错误解决方案&#xff1a; 总结 项目场景&#xff1a; keil5编译stm32例程在烧录时候遇到的一些问题 复位问题描述 1. 使…

全面解读LSC局域网屏幕监控软件:功能、优势与应用场景一网打尽!

在信息化高速发展的今天&#xff0c;企业管理的效率和精准度成为决定竞争力的关键因素。 LSC局域网屏幕监控软件&#xff08;LAN Screen Capture&#xff09;&#xff0c;作为安企神推出的一款专为现代企业量身打造的超级局域网监控管理软件&#xff0c;以其强大的功能和灵活的…

MAC环境导出项目的目录结构

一、安装Homebrew包管理工具 /bin/bash -c "$(curl -fsSL https://gitee.com/ineo6/homebrew-install/raw/master/install.sh)" 官网网址&#xff1a;https://brew.idayer.com/ 二、用brew包管理工具安装tree brew install tree 三、打开终端&#xff0c;导出项目…

怎么用AI做视频总结?

利用AI工具批量生成影视短剧推广https://docs.qq.com/doc/DYnl6d0FLdHp0V2ll 搞个插件就可以了。 我只能说AI的终极目的就是为了视频服务的&#xff0c;语音&#xff08;配音&#xff09;、视频脚本&#xff08;文案&#xff09;、绘图&#xff08;画面&#xff09;、设计&…

数据结构:单链表逆置的相关问题

1.思路&#xff1a;这里主要是用到头插法的思想进行单链表的一个逆置 2.知识点回顾&#xff1a; &#xff08;1&#xff09;头插法 &#xff3b;1&#xff3d;什么叫头插法&#xff1a;新增节点在头节点后面&#xff08;下图为单链表结构&#xff09; &#xff3b;2&#xf…

Leetcode 257-二叉树的所有路径

给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 题解 递归回溯 遇到叶节点返回 每层的做法,list加上当前节点的string值 本题解将res作为全局变量&#xff0c;作为局部变量写法也…

图像边缘检测Canny

一、Canny边缘检测原理 边缘检测是图像处理和计算机视觉中的基本问题&#xff0c;边缘检测的目的是标识数字图像中亮度变化明显的点。 Canny边缘检测算法是由4步构成&#xff1a;噪声去除、计算图像梯度、非极大值抑制、滞后阈值 1、噪声去除&#xff1a;由于边缘检测很容易受到…

Vulnhub靶场 | DC系列 - DC6

文章目录 DC-6环境搭建渗透测试 DC-6 环境搭建 靶机镜像下载地址&#xff1a;https://vulnhub.com/entry/dc-6,315/需要将靶机和 kali 攻击机放在同一个局域网里&#xff1b;本实验kali 的 IP 地址&#xff1a;192.168.10.146。 渗透测试 使用 nmap 扫描 192.168.10.0/24 网…

【报错已解决】`ValueError: Expected 2D array, got 1D array instead`的

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言&#xff1a; 在使用机器学习库&#xff08;如scikit-learn&#xff09;时&#xff0c;开发者可能会遇到ValueError: Expec…

Qt/C++地址转坐标/坐标转地址/逆地址解析/支持百度高德腾讯和天地图

一、前言说明 地址和经纬度坐标转换的功能必须在线使用&#xff0c;一般用在导航需求上&#xff0c;比如用户输入起点地址和终点地址&#xff0c;查询路线后&#xff0c;显示对应的路线&#xff0c;而实际上各大地图厂家默认支持的是给定经纬度坐标来查询&#xff08;百度地图…

光纤FPV无人机技术详解

1. 技术基础与原理 光纤FPV&#xff08;First Person View&#xff0c;第一人称视角&#xff09;无人机技术&#xff0c;是将光纤通信技术与无人机技术相结合的一项创新技术。该技术通过光纤作为高速、低延迟的数据传输媒介&#xff0c;实现了无人机拍摄的高清视频信号实时回传…

P0.9/P1.25全倒装共阴节能COB超微小间距LED显示屏已抢占C位

COB&#xff08;Chip on Board&#xff09;技术最早发源于上世纪60年代&#xff0c;是将LED芯片直接封装在PCB电路板上&#xff0c;并用特种树脂做整体覆盖。COB实现“点” 光源到“面” 光源的转换。点间距有P0.3、P0.4、P0.5、P0.6、P0.7、P0.9、P1.25、P1.538、P1.5625、P1.…