Try read(2) (in unistd.h ) and it should output 5 characters. When using libc ( fread(3) , fwrite(3) , etc.) you use the internal libc buffer, which usually has a page size (which is almost always 4 kiB).
I believe that when you first call fread for 5 bytes, libc does an internal read of 4096 bytes, and the next fread just returns bytes. Libc already has the structure you use in the buffer associated with the FILE . Until you reach 4096. The 4097th byte produces another read of 4096 bytes, etc.
This also happens when you write, for example, when using printf , which is just fprintf with stdout as the first argument. libc will not call write(2) directly, but instead puts your stuff in its internal buffer (also of 4096 bytes). It will be hidden if you call
fflush(stdout);
alone or at any time when byte 0x0a is sent (new line in ASCII).
Try it, you will see:
#include <stdio.h> #include <unistd.h> /* for sleep() */ int main(void) { printf("the following message won't show up\n"); printf("hello, world!"); sleep(3); printf("\nuntil now...\n"); return 0; }
However, this will work (without using libc buffering):
#include <stdio.h> #include <unistd.h> /* for sleep() and write() */ int main(void) { printf("the following message WILL show up\n"); write(0, "hello!", 6); sleep(3); printf("see?\n"); return 0; }
Of course, you should know that 0 is the default file descriptor for standard output.
Wetting every time a new line is important for the terminal user to instantly see messages, and also useful for processing in each line, which is a lot done in the Unix environment.
Thus, even if libc uses read and write syscalls directly to fill and flush its buffers (and by the way, the Microsoft implementation of the standard C library should use Windows stuff, possibly ReadFile and WriteFile ), these system calls absolutely do not know libc. This leads to interesting behavior when using both:
#include <stdio.h> #include <unistd.h> /* for write() */ int main(void) { printf("1. first message (flushed now)\n"); printf("2. second message (without flushing)"); write(0, "3. third message (flushed now)", 30); printf("\n"); return 0; }
which outputs:
1. first message (flushed now) 3. third message (flushed now)2. second message (without flushing)
(third - second!).
Also note that you can disable libc buffering with setvbuf(3) . Example:
#include <stdio.h> #include <unistd.h> /* for sleep() */ int main(void) { setvbuf(stdout, NULL, _IONBF, 0); printf("the following message WILL show up\n"); printf("hello!"); sleep(3); printf("see?\n"); return 0; }
I have never tried, but I think you could do the same with FILE* , which you get when fopen with your character device and disable I / O buffering for this:
FILE* fh = fopen("/dev/my-char-device", "rb"); setvbuf(fh, NULL, _IONBF, 0);