请注意使用在C语言中进行缓存的API和不进行缓存的系统调用的组合
【摘要】
在一个将文本字符串写入文件的程序中,首先调用一个进行缓冲处理的API,然后再调用一个不进行缓冲处理的系统调用,来确认输出结果。由于API进行了缓冲处理,所以通过系统调用输出的字符串将先被输出。
###【环境】
###【Environment】
[root@vagrant-centos65 buff]# cat /etc/centos-release
CentOS release 6.5 (Final)
###【代码】
该代码接收一个参数作为文件,并在该文件中写入字符串的过程。
如果有缓冲区
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
FILE *f;
char *apiStr = "Hello, API\n";
char *systemCallStr = "Hello, system call\n";
if((f = fopen(argv[1], "w")) == NULL) {
puts("fopen error");
exit(1);
}
// fputsはバッファリングされる
fputs(apiStr, f);
// システムコールであるwriteはバッファリングされないため、即出力される
if (write(fileno(f), systemCallStr, strlen(systemCallStr)) < 0) exit(1);
fclose(f);
exit(0);
}
执行结果
[root@vagrant-centos65 buff]# gcc -o buffer buffer.c
[root@vagrant-centos65 buff]# ./buffer buffer.txt
[root@vagrant-centos65 buff]# cat buffer.txt
Hello, system call
Hello, API
如果没有缓冲的话
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
FILE *f;
char *apiStr = "Hello, API\n";
char *systemCallStr = "Hello, system call\n";
if((f = fopen(argv[1], "w")) == NULL) {
puts("fopen error");
exit(1);
}
// バッファリングしないよう設定
// あるいは、fputsした後にfflushでもOK
setbuf(f, NULL);
// 即出力される
fputs(apiStr, f);
// 即出力される
if (write(fileno(f), systemCallStr, strlen(systemCallStr)) < 0) exit(1);
fclose(f);
exit(0);
}
执行结果
[root@vagrant-centos65 buff]# gcc -o no_buffer1 no_buffer1.c
[root@vagrant-centos65 buff]# ./no_buffer1 no_buffer1.txt
[root@vagrant-centos65 buff]# cat no_buffer1.txt
Hello, API
Hello, system call
总结:文件描述符和FILE之间可以自由转换,但是由于缓冲区可能导致输入输出顺序混乱,所以不应该随意混合使用这两者。
###【额外内容】
尽管printf应该具有缓冲功能,但API的输出似乎比系统调用更快。
[补充说明] 根据angel_p_57的评论
默认情况下,引用终端设备的输出流始终以行为单位进行缓冲处理。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char *apiStr = "Hello, API\n";
char *systemCallStr = "Hello, system call\n";
printf("%s", apiStr);
if (write(STDOUT_FILENO, systemCallStr, strlen(systemCallStr)) < 0) exit(1);
exit(0);
}
执行结果
[root@vagrant-centos65 buff]# gcc -o no_buffer2 no_buffer2.c
[root@vagrant-centos65 buff]# ./no_buffer2
Hello, API
Hello, system call
###【参考书】
《普通的Linux编程 第2版》 从Linux的机制中学习gcc编程的王道