stdio Buffers
stdio Buffers in C
What if you want to write a program that displays the classic busy indicator (commonly called a spinner) in C?
You can use the '\b' escape sequence to delete the previous character on most terminals and wait for around 1 second before printing the next character.
Will this work though?
Not the expected? What's wrong?
The thing is before interacting with the output device, the terminal in this case, the program (or better yet the process) will put all the characters in the buffer, that buffer is the stdout buffer provided by the stdio library which is responsible for the streams and maintains them as well.
A buffer is a temporary storage for the data when it is being shared between two devices. It is usually used to reduce the number of I/O calls to the kernel, in the case of stdout, if there was no buffer, whenever the program had to write to a device, it had to get access of it competing among other devices and then wait until the device (mostly operating at a fraction of the CPU speed) would complete the I/O task. A buffer allows the program to store its result in a temporary space before invoking system call to get the I/O done.
And this buffer is flushed out i.e. the characters displayed on the terminal only when it is filled completely (mostly 4kB size) or the program terminates, or a newline character is encountered. This is called line buffering.
So, what we need is no buffer between the programs output and the output device, there is a stream stderr which generally has no buffer (unbuffered) in place.
So, we give the output through the stderr stream and we can get the input directly to the terminal. Also there is a utility fflush which allows us to directly flush the characters stored in the stdout buffer to the terminal. Hence both the below programs are equivalent.
| Using stderr as output stream |
| flushing characters in stdout buffer |
Note: Just as the stdout, the stdin associated with input (for example terminal) also has a buffer to communicate with input devices. Same like stdout (mostly) it also is line buffered.
All these buffering rules can be overridden using setvbuf and setbuf.
The prototype for setbuf is
void setbuf( FILE *restrict stream, char *restrict buffer );
The buffer is the pointer to the buffer for the stream to use, if NULL, the buffering is turned off.
The prototype for setvbuf is
int setvbuf( FILE *restrict stream, char *restrict buffer, int mode, size_t size );
Modes:
_IONBF no buffering
_IOLBF line buffering
_IOFBF full buffering
Thanks for reading, please highlight any inconsistencies in comments.
References:
Cool. Thanks man!
ReplyDelete<3
Delete