Linux系统调用一、系统调用与C库函数的关系 —— 从进程虚拟地址空间和文件描述符的角度分析

简介: Linux系统调用一、系统调用与C库函数的关系 —— 从进程虚拟地址空间和文件描述符的角度分析

当我们在C语言程序中调用一个库函数的时候,比如调用printf()函数,实际上它是通过文件指针来指向要打印的位置的。并且,printf()函数会调用Linux的系统函数write()函数(它是一个系统接口,也可以人工调用),write()函数再继续调用sys_write()函数(这个函数只能是操作系统去调用),sys_write()继续调用设备驱动,具体调用哪个驱动要看输出的位置,如果是printf()打印到显示器上,那么就调用显示器驱动并打印在屏幕上,如果是写到网络上,就会调用网卡驱动。我们所作的只有在C程序中调用printf()等库函数,其余操作都是操作系统帮我们做的。请看下面这张图。

printf()函数在打印的时候通过一个文件指针来实现打印到某个文件的某个位置。在文件在文件指针中,包含了一个文件描述符,这个文件描述符用于指定目标文件,默认情况下就是STDOUT_FILENO也就是标准输出1号描述符;f_pos指定了读写的位置,比如我们打印的时候他会不停的在上一次打印的末尾位置打印后面的内容,就是通过这个位置去实现的;在最后还有一个缓冲区buffer,那么为什么要有buffer缓冲区呢,其实这是为了提高读写的效率,把读写的内容先放到缓冲区,这样就可以实现一次读写更多的内容。并且,这个缓冲区需要刷新才能得到输入输出,我们可以通过下面程序来测试一下。

测试文件01_print_dm.c

/************************************************************
  >File Name  : 01_print_dm.c
  >Author     : QQ
  >Company    : QQ
  >Create Time: 2022年05月12日 星期四 15时28分15秒************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{   
    close(1);
    int fd = open("test.log", O_CREAT | O_TRUNC | O_WRONLY, 0644);
    printf("hello ... \n");
    fflush(stdout);
    close(fd);
    return 0;
}

编译文件makefile

.PHONY:all clean
CC=gcc
CFLAGS=-Wall -g
EXE=01_print_dm
all:$(EXE)
%.o:%.c
  $(CC) $(CFLAGS) -c $< -o $@
clean:
  -@rm -f *.o $(EXE)

在这个程序中close(1);表示关闭标准输出,在前面我们已经说过文件描述符1代表标准输出,这时候通过open()打开一个文件,我们知道,当打开一个文件的时候会使用一个当前空闲的最小文件描述符,因为前面我们把标准输出关闭了,所以当前空闲的最小文件描述符1分配给open()函数打开的文件。虽然1号文件描述符当前已经不是标准输出(终端显示屏)了,但是stdout依然是指向1号文件描述符的,实际上这就相当于把open()打开的文件当作标准输入输出,printf()打印的内容都会打印到test.log文件内。首先我们屏蔽fflush()函数试一下

这个test.log文件内是空的,也就是说,如果不刷新缓冲区的话,无法正常打印内容,我们把刷新函数fflush()加上就可以看到,printf()函数打印内容直接打印到test.log文件内了,而不会打印在终端。

实际上,在Linux下启动一个进程,就会默认打开三个文件描述符:0标准输入、1标准输出、2标准错误。它们分别对应C语言中的stdin、stdout、stderr。当我们每次打开一个文件,就会分配给这个文件一个当前空闲的最小文件描述符,如果此时标准输入0、标准输出1、标准错误2空闲,那么也会把这个文件描述符分配给新打开的文件但是这三个文件描述符0、1、2与stdin、stdout、stderr的对象关系不会变,并且在后续的操作中会把0、1、2指向的新文件当作标准输入输出和标准错误去处理,并将输入输出或错误信息打印到这个文件。

相关文章
|
7天前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
30 4
|
26天前
|
Linux
Linux:守护进程(进程组、会话和守护进程)
守护进程在 Linux 系统中扮演着重要角色,通过后台执行关键任务和服务,确保系统的稳定运行。理解进程组和会话的概念,是正确创建和管理守护进程的基础。使用现代的 `systemd` 或传统的 `init.d` 方法,可以有效地管理守护进程,提升系统的可靠性和可维护性。希望本文能帮助读者深入理解并掌握 Linux 守护进程的相关知识。
37 7
|
25天前
|
Linux Shell
Linux 进程前台后台切换与作业控制
进程前台/后台切换及作业控制简介: 在 Shell 中,启动的程序默认为前台进程,会占用终端直到执行完毕。例如,执行 `./shella.sh` 时,终端会被占用。为避免不便,可将命令放到后台运行,如 `./shella.sh &`,此时终端命令行立即返回,可继续输入其他命令。 常用作业控制命令: - `fg %1`:将后台作业切换到前台。 - `Ctrl + Z`:暂停前台作业并放到后台。 - `bg %1`:让暂停的后台作业继续执行。 - `kill %1`:终止后台作业。 优先级调整:
42 5
|
25天前
|
Linux 应用服务中间件 nginx
Linux 进程管理基础
Linux 进程是操作系统中运行程序的实例,彼此隔离以确保安全性和稳定性。常用命令查看和管理进程:`ps` 显示当前终端会话相关进程;`ps aux` 和 `ps -ef` 显示所有进程信息;`ps -u username` 查看特定用户进程;`ps -e | grep &lt;进程名&gt;` 查找特定进程;`ps -p &lt;PID&gt;` 查看指定 PID 的进程详情。终止进程可用 `kill &lt;PID&gt;` 或 `pkill &lt;进程名&gt;`,强制终止加 `-9` 选项。
25 3
|
7月前
|
Linux
Linux0.11 文件打开open函数(五)
Linux0.11 文件打开open函数(五)
92 0
|
10月前
|
Linux 开发者
Linux文件编程(open read write close函数)
通过这些函数,开发者可以在Linux环境下进行文件的读取、写入和管理。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
205 4
|
10月前
|
存储 Linux
Linux文件编程(open read write close函数)
Linux文件编程(open read write close函数)
297 0
|
Linux
Linux系统调用二、open()函数与close()函数介绍
Linux系统调用二、open()函数与close()函数介绍
413 0
Linux系统调用二、open()函数与close()函数介绍
|
Linux
Linux系统中利用open函数多次打开同一个文件操作方法
大家好。 今天的话主要和大家聊一聊,在Linux系统中如果一个文件被打开多次会出现什么情况。
722 0
Linux系统中利用open函数多次打开同一个文件操作方法
|
Linux C++ Unix