携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
💦 理解 “ Linux 下,一切皆文件 ”
-
这里我们就要校准一个概念,不是任何 C 程序运行会默认打开,而是进程在启动时,会默认三个 “ 文件 ”,分别是标准输入(stdin)、标准输出(stdout)、标准错误(stderr)。这里可以看到它们三个的类型与用于接收 fopen 的返回值类型是一样的。
-
默认情况下,标准输入是键盘文件,标准输出是显示器文件,标准错误是显示器文件。而这三个本身是硬件,如何理解 Linux 中,一切皆文件❓
所有的外设硬件,本质对应的核心操作无外乎是 read 或 write。对于键盘文件,它的读方法就是从键盘读取数据到内存;它的写方法设置为空,因为没有把数据写到键盘上这种说法。
对于显示器文件,如调用 printf 函数时,操作系统是要往显示器上写入的;理论上操作系统是不会往显示器上读数据的,所以设置为空?不对呀,我们在命令行输入命令显示在 Xshell 上,系统要执行命令时不就是往显示器上读吗?—— 如果是往显示器上读,那么你在输入密码时,密码是不显示的,系统也能往显示器上读吗。其实你输入的命令是你通过键盘输入的,所以系统应该是往键盘读数据。至于用户能看到输入的命令,仅仅是为了方便用户,操作系统把从键盘输入的数据,一方面给了系统读取,一方面给显示器方便用户。
所以不同的硬件,对应的读写方式肯定是不一样的,但是它们都有 read 和 write 方法,换言之,这里的硬件可以统一看作一种特殊的文件。比如这里设计一种结构叫做 struct file,它包括文件的属性、文件的操作或方法等,Linux 说一切皆文件,Linux 操作系统就必须要保证这点。在 C 语言中,怎么让一个结构体既有属性,也有方法呢?—— 函数指针。此时每一个硬件都对应这样一个结构,硬件一多,操作系统要对它们进行管理 —— 六字箴言,先描述,在组织。所谓的描述就是 struct file;组织就是要把每一个硬件对应的结构体关联起来,并用 file header 指向。所以在操作系统的角度,它看到的就是一切皆文件,也就是说所有硬件的差异,经过描述,就变成了同一种东西,只不过当具体访问某种设备时,使用函数指针执行不同的方法,就达到了不同的行为。现在就能理解为什么可以把键盘、显示器当作文件,因为本质不同设备的读写方法是有差异的,但我们可以通过函数指针让不同的硬件包括普通文件在操作系统看来是同样的方法、同样的文件。
#include<stdio.h>
#include<string.h>
int main()
{
const char* msg = "Hello DanceBit\n";
fwrite(msg, strlen(msg), 1, stdout);
char buffer[64];
fread(buffer, 1, 10, stdin);//你输入时没有写\0,fread时也不会加,所以一旦超过10,就会出现乱码
buffer[10] = '\0';
printf("%s\n", buffer);
return 0;
}
-
这里可以直接使用 fwrite 这样的接口,向显示器写数据的原因是因为 C 程序一运行,stdout 就默认打开了。同理 fread 能从键盘读数据的原因是 C 程序一运行,stdin 就默认打开了。
-
也就是说 C 接口除了对普通文件进行读写之外(需要打开),还可以对 stdin、stdout、stderr 进行读写(不需要打开)。
为什么 C 程序运行,就会默认打开 stdin、stdout、stderr?仅仅是 C 吗 ❓
scanf -> 键盘、printf -> 显示器、perror -> 显示器,换言之,如果不打开,那么作为程序员是不能直接调用这些接口的,所以默认打开的原因是便于程序员直接上手,且大部分编码都会有输入输出的需求。也就是说 scanf、printf、perror 这样的库函数,底层一定使用了 stdin、stdout、stderr 文件指针来完成不同的功能。此外还有些接口和 printf、scanf 很像,它本身是把使用的过程暴露出来,比如 fprintf(stdout, "%d, %d, %c\n", 12, 24, b)。
这里可以否定的,C 程序运行才会打开 stdin、stdout、stderr。而几乎所有语言都是这样的,C++ 中是 cin、cout、cerr,所以你会发现一个现象,不管是学习啥语言,第一个程序永远是 Hello World!。这里说几乎所有语言都这样的,意味着不仅仅是语言层提供的功能了,比如一条人山人海的路从头到尾只有个别商贩在摆摊,那么我们认为这是商贩的个人行为,当地的管理者是排斥这种行为的;但如果一条人山人海的路从头到尾都有商贩在摆摊,那么我们认为当地的管理者是支持这种行为的;同样不同语言彼此之间没有进行过任何商量,而最终都会默认打开,所以这不仅仅是语言支持的,也一定是操作系统支持的,一会再细谈。