[LINUX] [C language] Be careful of the combination of buffering API and non-buffering system call

【Overview】

Check the output result of calling the API that buffers the string in the program that writes it to the file first, and then the system call that does not buffer. Since the API buffers, the character string output by the system call is output first.

【environment】

[root@vagrant-centos65 buff]# cat /etc/centos-release 
CentOS release 6.5 (Final)

【code】

It is a process of passing a file as a parameter and writing a character string to that file.

① With buffering

buffer.c


#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 are buffered
	fputs(apiStr, f);
	//The system call write is not buffered, so it is output immediately.
	if (write(fileno(f), systemCallStr, strlen(systemCallStr)) < 0) exit(1);
	fclose(f);
	exit(0);
}
Execution result
[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

② When there is no buffering

no_buffer1.c


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

	//Set not to buffer
	//Alternatively, fflush is OK after fputs
	setbuf(f, NULL);

	//Immediate output
	fputs(apiStr, f);
	//Immediate output
	if (write(fileno(f), systemCallStr, strlen(systemCallStr)) < 0) exit(1);
	fclose(f);
	exit(0);
}
Execution result
[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

[Summary]

The file descriptor and FILE can be moved back and forth freely, but it seems that you should not mix the two easily because the buffer may cause the input / output order to be out of order.

【bonus】

The printf should be buffered, but the API is printed before the system call. [Addition] From the comment of angel_p_57

The output stream that references the terminal device is always buffered line by line by default.

no_buffer2.c


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

Execution result

[root@vagrant-centos65 buff]# gcc -o no_buffer2 no_buffer2.c 
[root@vagrant-centos65 buff]# ./no_buffer2
Hello, API
Hello, system call

【Reference book】

[Normal Linux programming 2nd edition: The royal road of gcc programming that can be learned from the mechanism of Linux](https://www.amazon.co.jp/%E3%81%B5%E3%81%A4%E3%81%86% E3% 81% AELinux% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0-% E7 % AC% AC2% E7% 89% 88-Linux% E3% 81% AE% E4% BB% 95% E7% B5% 84% E3% 81% BF% E3% 81% 8B% E3% 82% 89% E5 % AD% A6% E3% 81% B9% E3% 82% 8Bgcc% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83 % B3% E3% 82% B0% E3% 81% AE% E7% 8E% 8B% E9% 81% 93-% E9% 9D% 92% E6% 9C% A8-% E5% B3% B0% E9% 83 % 8E-ebook / dp / B075ST51Y5)

Recommended Posts

[C language] Be careful of the combination of buffering API and non-buffering system call
How to limit the API to be published in the C language shared library of Linux
The story of porting code from C to Go and getting hooked (and to the language spec)
Be careful when differentiating the eigenvectors of a matrix
[C language] [Linux] Get the value of environment variable
Call the C function with dart: ffi and call the Dart function callback
Call the API of Hatena Blog from Python and save your blog articles individually on your PC
Let's cross the wall of the left-handed coordinate system and the right-handed coordinate system.
I tried to illustrate the time and time in C language
100 language processing knock-42: Display of the phrase of the person concerned and the person concerned