Explanation of I/O buffer in C

Source: Internet
Author: User
Tags exit in
Interpretation of the I/O buffer in C the I/O buffer of the C standard library the user program calls the C standard I/O library function to read and write files or devices, these database functions need to pass the read/write requests to the kernel through system calls, and the kernel drives the disk or device to complete the I/O operations. The C standard library allocates an I/O buffer for each opened file to accelerate read/write operations. This buffer can be found through the file structure of the file, most of the time a user calls a read/write function, the read/write requests are read and written in the I/O buffer. Only a few requests need to be sent to the kernel. Taking fgetc/fputc as an example, when a user program calls fgetc to read a byte for the first time, the fgetc function may read 1 kb of bytes to the I/O buffer through the system call, then, the first byte in the I/O buffer is returned to the user, pointing the read/write position to the second character in the I/O buffer, and then the user calls fgetc, it is read directly from the I/O buffer, instead of the kernel. When the user reads all the 1 K bytes and calls fgetc again, the fgetc function will read 1 K bytes into the I/O buffer again. In this scenario, the relationship between the user program, the C standard library, and the kernel is the same as that between the CPU, cache, and memory, the reason why the C standard library will pre-read some data from the kernel and put it in the I/O buffer is that the user program will use the data later, and the C standard library's I/O buffer is also in the user space, reading data directly from the user space is much faster than reading data into the kernel. On the other hand, when a user program calls fputc, it is usually written to the I/O buffer, so that the fputc function can return quickly. If the I/O buffer is full, fputc transmits the data in the I/O buffer to the kernel through a system call, and the kernel writes the data back to the disk. Sometimes, the user program wants to immediately pass the data in the I/O buffer to the kernel and write the data back to the device. This is called the flush operation. The corresponding library function is fflush, the fclose function will also perform the flush operation before closing the file. Fgets/fputs indicates the role of the I/O buffer. When using the fgets/fputs function, the user program also needs to allocate a buffer (buf1 and buf2 in the figure ), note that the user program buffer and the C standard library I/O buffer are distinguished. C Standard library I/O Buffer: C standard library I/O buffer has three types: Full buffer, row buffer and no buffer. When a user program calls a database function for write operations, different types of buffers have different features. Full buffer writes back to the kernel if the buffer is full. Regular files are generally fully buffered. Line Buffer writes this line back to the kernel if there is a line break in the data written by the user program, or if the buffer is full, it writes back to the kernel. Standard input and standard output are usually used as row buffering for terminal devices. The user program without buffering writes data back to the kernel every time the function is called. Standard Error output is usually unbuffered, so that the error messages generated by the user program can be output to the device as soon as possible. The following is a simple example to show that the standard output is a line buffer for the corresponding terminal device. # Include <stdio. h> int main () {printf ("Hello World"); While (1); Return 0;} run this program, you will find that Hello World is not printed to the screen. Use ctrl-C to terminate it and remove the while (1); statement in the program and try again: $. /. out Hello World $ Hello world is printed to the screen, followed by a shell prompt without line breaks. We know that the main function is called as follows by the startup code: exit (main (argc, argv ));. When the main function returns, the startup code will call exit. The exit function first closes all file * pointers that have not been closed (the flush operation is required before closing ), then, run the _ exit system call to enter the kernel and exit the current process. In the preceding example, because the standard output is row buffered, printf ("Hello World"); the printed string does not contain line breaks, therefore, only the string is written to the standard output I/O buffer and not written back to the kernel (written to the terminal device). If you press Ctrl-C, the process stops unexpectedly and does not call exit, there is no chance to flush I/O the buffer, so the string is not printed to the screen. If you change the print statement to printf ("Hello world \ n"); with a line break, it is immediately written to the terminal device, or if you change the while (1 ); you can also remove it from the terminal device because it calls exitflush all I/O buffers when the program exits. In other examples in this book, the strings printed by printf have line breaks at the end to ensure that the strings are written to the terminal device at the end of the printf call. Let's make another experiment and directly call _ exit in the program to exit. # Include <stdio. h> # include <unistd. h> int main () {printf ("Hello World"); _ exit (0);} the result does not print the string to the screen, if you change the _ exit call to exit, you can print it to the screen. In addition to writing full buffers and line breaks, row buffering also automatically performs flush operations. If the user program calls the library function to read from the unbuffered file or from the row-buffered file, in addition, this read operation will cause the system to call to read data from the kernel, so all row buffering will be automatically flushed before reading. Example: # include <stdio. h> # include <unistd. h> int main () {char Buf [20]; printf ("Please input a line:"); fgets (BUF, 20, stdin); Return 0 ;} although the call to printf does not write the string to the device, the call to fgets to read a row-buffered file (standard input) will automatically flush all row buffering, including standard output, before reading. If your program does not want to rely entirely on the automatic flush operation, you can call the fflush function to manually perform the flush operation. # Include <stdio. h> int fflush (File * stream); returned value: 0 is returned for success, EOF is returned for error, and errno is set to slightly modify the previous example: # include <stdio. h> int main () {printf ("Hello World"); fflush (stdout); While (1) ;}although there is no line break in the string, however, the user program calls fflush to forcibly write back to the kernel, so it can print a string on the screen. The fflush function is used to ensure that data is written back to the kernel to avoid data loss during abnormal Process Termination. As a special case, calling fflush (null) can flush all the I/O buffers that open files. To sum up, the I/O buffer in the C language is like this: for the printf function, row buffering, data will be output on the screen every time the output has a line break or the output exceeds the buffer size. There are two exceptions: 1. when reading data output from an unbuffered file (or data stream); 2. when printf is followed by scanf, because scanf is a row-buffered stream, and the call to scanf will cause the system to write data to the inner core, printf will automatically flush. For the scanf function, the row buffer sends data together with the line break at the end of each input to the buffer, and then the buffer has a "Pointer ", always point to the character currently read (that is, the "current character Pointer "). When a character is sent from the buffer to a specific variable in the memory, the character in the buffer is cleared. (The line break entered by the carriage return is treated as a space character ''in the buffer ). It is worth noting that each scanf checks whether there are unread characters after the "current character Pointer" in the buffer zone. In this way, when the scanf % C data is continuous, it is possible to directly assign the line break at the end of the data to the character variable to be entered next. Example: (think) a small program contains the following statements: Char C1, C2; scanf ("% C", & C1); printf ("% C", C1 ); scanf ("% C", & C2); printf ("% C", C2); in this way, enter C1 after run, and press enter to enter C2, the program has ended. Why? Modify "scanf (" % C ", & C2); printf (" % C ", C2);" to "scanf (" % s ", & C2); printf ("% C", C2); but yes. Why? What is the difference between % s and % C? (% S to read the first non-null character) there is another method: scanf ("% C", & Ch); changed to scanf ("% C", & Ch ); % C is preceded by a space. Why? Http://blog.sina.com.cn/s/blog_49a8f7b10100n2ki.html

 

Explanation of I/O buffer in C

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.