Today hastily the fourth chapter knot, the back of the content analysis is not very detailed, even the book examples are not how to experiment, or wait for a chance later.
Starting with section 5.3, this section focuses on 3 streams that are predefined for a process, namely standard input, standard output, and standard error, referenced by stdin, stdout, and stderr. This is to be distinguished from the file descriptor Stdin_fileno, Stdout_fileno, Stderr_fileno in the process.
/* standard streams. */extern struct _io_file *stdin;/* standard input stream. */extern struct _io_file *stdout;/* standard output stream. */extern struct _io_file *stderr;/* standard error output stream. *//* c89/c99 say they ' re macros. Make them happy. *///This sentence is the most interesting, make them happy # # stdin stdin#define stdout stdout#define stderr stderr
5.4 Buffering
Standard I/O provides the following 3 types of buffering:
- Fully buffered. In this case, the actual I/O operations are not performed until the standard I/O buffers are filled.
- Row buffers. In this case, the standard I/O library performs I/O operations when a newline character is encountered in the input and output. Row Buffering allows one character to be output at a time (FPUTC with a standard I/O function), but only after a line has been written for actual I/O operations. Row buffering is typically used when a stream involves a terminal, such as standard input and standard output. There are two restrictions for row buffering. First, because the length of the buffer used by the standard I/O library to collect each row is fixed, so that only the buffer is filled, I/O is done even if a newline character has not been written. Second, any time a standard I/O library is required to obtain input data from (a) a non-buffered stream, or (b) a row-buffered stream (which requests data from the kernel), all row buffered input streams are flushed. Flushing here refers to writing the data in the buffer to the kernel. In (b) There is a note in parentheses, on the grounds that the required data may already be in the buffer, and it does not require that the data be read from the kernel. It is clear that the input from a non-buffered stream (that is, (a)) requires the data to be obtained from the kernel.
- With no buffering. The standard I/O library does not buffer characters for storage.
For the 2nd mentioned above can be verified by a few simple experiments, through the FPUTC to the standard output input data, the specific program is as follows:
#include <stdio.h> #include <unistd.h>int main (void) { char msg[] = "Hello world"; int i = 0; while (Msg[i]) { FPUTC (Msg[i], stdout);//Change the FPUTC function to the same printf effect sleep (1);//After writing the program hangs 1s i++; } return 0;}
Running results: The program does not output, the final unified output MSG, through this program basically verify the characteristics of the row buffer, there is no line break or write full line buffer, do not perform I/O operations, but also verify the standard I/O using the row buffer mode. But this experiment has led to a problem that is the timing of the I/O operation, in the above experiment I did not output newline characters, but also did not write full buffer, now put this question down, learn the back of the knowledge may be able to answer.
Standard I/O buffering also has the following conventions:
- Standard errors are non-buffered.
- If the flow to the terminal device is a line buffer, otherwise it is fully buffered.
You can change the buffer type by using the following function.
#include <stdio.h>extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __throw;extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf, int __modes, size_t __n) __throw;
The above function must be used after the stream has been opened. It should also be called before any other operation is performed on the stream.
The function of the setvbuf is quite clear and the modes parameter can be used to set the buffering mode:
#include <stdio.h> #define _IOFBF 0/* Fully buffered. */#define _IOLBF 1/* line buffered. */#define _IONBF 2/* No buffering. */
Force flushing of a stream.
#include <stdio.h>extern int fflush (FILE *__stream);
If the FP is null, this function causes all output streams to be flushed.
5.5 Open stream
extern file *fopen (const char *__restrict __filename, const char *__restrict __modes) __wur;extern file *freopen (con St Char *__restrict __filename, const char *__restrict __modes, FILE *__restrict __stream) __wur ; extern FILE *fdopen (int __fd, const char *__modes) __throw __wur;
The differences between the above three functions are as follows:
- The fopen function opens a specified file with the path named pathname.
- The Freopen function opens a specified file on a specified stream, and if the stream is already open, the stream is closed first. If the stream is already directed, use Freopen to clear the orientation. This function is typically used to open a specified file as a predefined stream: standard input, standard output, or standard error.
- The Fdopen function takes an existing file descriptor (which can be obtained by using the Open function) and combines a standard I/O stream with the descriptor. This function is commonly used for descriptors returned by the Create pipeline and network communication channel functions. Because these special types of files cannot be opened with the standard I/O function fopen, we must first call the device-specific function to obtain a file descriptor and then use fopen to combine a standard I/O stream with the descriptor.
ISO specifies that the type parameter can have 15 different values.
- R or RB: open for reading. However, the file must already exist. (o_rdonly)
- W or WB: Truncate the file to 0 long, or create it for writing. The content before the file is deleted. (o_wronly| O_creat| O_TRUNC)
- A or AB: Append, open for writing at the end of the file, or open for writing. (o_wronly| O_creat| O_append)
- r+ or R+b or rb+: Open for Read and write. The stream can only be written at the end. (O_RDWR)
- w+ or W+b or wb+: Truncate the file to 0 long, or open for read and write. (o_rdwr| O_creat| O_TRUNC)
- A + or a+b or ab+: opened or created for read and write at the end of a file. (o_rdwr| O_creat| O_append)
For the type explanation see: http://www.cnblogs.com/emanlee/p/4418163.html
Because the kernel does not differentiate between text files and binary files. So B does not actually work as part of type.
For the Fdopen function, if the descriptor is open, Fdopen is open for writing and does not truncate the file. Also, the standard I/O append write (A or a +) cannot be used to create the file (because if a descriptor references a file, the file must already exist).
When you create a new file using the W or a type, POSIX.1 requires that you create the file with the following permissions:
s_irusr| s_iwusr| s_irgrp| s_iwgrp| s_iroth| S_iwoth
You can change permissions by unmask values.
By default, the stream is fully buffered when it is opened. If a stream refers to an end device, it is a row buffer.
Call Fclose to close an open stream.
#include <stdio.h>extern int fclose (FILE *__stream);
Flush the output data in the buffer before the file is closed. Any input data in the buffer is discarded.
When a process terminates normally (calling the Exit function directly or returning from the main function), all standard I/O streams with write buffered data are flushed and all open standard I/O streams are closed. This also explains the question we left before, the timing of data flushing in the buffer-when the process normally terminates, according to the knowledge we learned before, it should be that a destructor is registered before the main function begins, and the function of the destructor is to flush the buffer.
5.6 Read and Write streams
Standard I/O provides three ways of unformatted read and write operations.
- I/O for one character at a time.
- I/O for each line. Each line terminates with a newline character.
- Direct I/O.
I/O for one character at a time. Because the standard I/O is in row buffer mode, the buffer is flushed only if a newline character or a line is written, and the data is written to the buffer. The input functions are as follows:
#include <stdio.h>extern int fgetc (file *__stream), extern int getc (file *__stream), extern int getchar (void); function GetChar () is equivalent to GETC (stdin)
The specific implementation of GETC is:
#include <stdio.h> #define GETC (_FP) _io_getc (_FP)
The reason for using int as the return value is to return all possible character values in addition to an indication that an error has occurred or that the end of the file has been reached. I checked, too. The following is an ASCII code table that already contains 128 symbols, so using char as the return data is far from enough.
The definition of EOF is
#include <stdio.h> #ifndef eof# define EOF ( -1) #endif
EOF is returned for reaching the end of a file or an error, so in order to further differentiate between the two cases, two functions are introduced:
#include <stdio.h>extern int feof (FILE *__stream) __throw __wur; If the end of the file is reached, the return is not 0, otherwise the 0extern int ferror (file *__stream) __throw __wur is returned; If the input error, return is not 0, otherwise return 0
Two flags are maintained for each stream in the file object.
- The error flag.
- The end of file flag.
Because feof only checks whether the file end flag bit is set, the end-of-file flag is determined by the last related operation (including Read, Seek, and so on) before the current time. Therefore, it is not possible to call feof before the Fgets function to determine whether the file stream reaches the trailer. For a solution to this problem, see: http://book.51cto.com/art/201311/419432.htm
Call Clearerr to clear both flags.
#include <stdio.h>extern void Clearerr (FILE *__stream) __throw;
After reading the data from the stream, you can call ungetc to re-press the character back into the reflow.
#include <stdio.h>extern int ungetc (int __c, FILE *__stream);
I/O for one character at a time. Output function:
#include <stdio.h>extern int fputc (int __c, file *__stream), extern int putc (int __c, file *__stream), #define PUTC ( _ch, _FP) _IO_PUTC (_ch, _FP) extern int Putchar (int __c);
5.7 I/O per line
Section 5.6 mainly analyzes the i/o,5.7 section of one character at a time to describe I/O for each row.
First look at the input function:
#include <stdio.h>extern Char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)//read from specified stream __wur;ex Tern Char *gets (char *__s) __wur __attribute_deprecated__; Read from standard input
Because it is standard I/O, it is read until the next line break, but not more than n-1 characters. The buffer ends with a null byte. If the line includes the last newline character more than n-1, Fgets returns only an incomplete row, but the buffer always ends with a null byte. The next call to Fgets will continue to read the row.
Let's take a look. The next call to Fgets will continue to read the row, passing a validation. The source code is as follows:
#include <stdio.h> #include <stdlib.h>int main () {file* fp;char* buf1 = (char*) malloc (4*sizeof (char)); char* Buf2 = (char*) malloc (7*sizeof (char)), FP = fopen ("./temp", "R"), Fgets (BUF1,4,FP);p rintf ("%s\n", buf1); Fgets (BUF2,7,FP );p rintf ("%s\n", buf2); free (BUF1); free (buf2); return 0;}
The content in the temp file is also the familiar "Hello World"
The results of the operation are as follows:
Hello Wor
According to the knowledge we learned before, Fgets will read the n-1 characters without reading the newline character, the length of the BUF1 is 4, so it will read three characters, namely "Hel", and the first line of output confirms this knowledge point.
As standard I/O uses the row buffer mode, based on the results of the experiment, I guess that fgets will populate the buffer with a one-time reading of a certain length of data, and each call to the Fgets function reads n-1 characters from the buffer until the data is read out. But if the data contains newline characters, then I/O operations are performed, and here is the output to the screen.
Because the data in the buffer is not read all, Fgets continues to read the row. This is also verified by the second line of the output.
Or do not understand from the source point of view, only from the functional perspective of the features of the function, fgets one is to read a row, if it contains a newline character, it actually means that the data is not a row but two lines. After reading a row of data, fgets copies the n-1 characters into the user buffer, knowing that the data in the buffer is all read out. As described above, we can implement a simple fgets function ourselves. The execution flow of the function is as follows:
- Determines whether the current position pointer is 0, or if 0 jumps directly to 4 execution, otherwise the order is executed.
- Read the data and, if you encounter "\ n", jump out of the loop, otherwise read until the buffer is full.
- First set the current position pointer to the head of the buffer.
- Calculates the number of characters copied, or copies the data that is actually contained in the buffer if the buffer contains enough data to replicate the user-specified number of bytes.
- The last position of the user buffer is "\".
- Updates the current position pointer.
fgets function of the source code in this will not be detailed analysis, and strive to fread the source of a simple analysis.
The output function, one line at a time.
A newline character is also written to standard output after the puts output.
5.9 Binary I/O
The main function of binary I/O is to read or write data of any type, any byte, where two parameters are similar to the parameters contained in the MPI interface.
Function prototype Type:
#include <stdio.h>extern size_t fread (void *__restrict __ptr, size_t __size, size_t __n, FILE *__restrict __str EAM) __wur;extern size_t fwrite (const void *__restrict __ptr, size_t __size, size_t __n, FILE *__restrict __s);
Returns the number of objects read or written. For write, an error occurs if the return value is less than the requested __n. Can be checked by ferror.
5.12 Implementation Details
The file descriptor corresponding to the file stream pointer can be obtained by using the following function.
#include <stdio.h>extern int Fileno (FILE *__stream) __throw __wur;
The definition for the file structure is as follows, in Libio.h
struct _io_file {int _flags;/* high-order Word is _io_magic, rest is flags. */#define _IO_FILE_FLAGS _flags/* The Foll Owing pointers correspond to the C + + STREAMBUF protocol. */* NOTE:TK uses the _io_read_ptr and _io_read_end fields directly. */char* _io_read_ptr;/* Current Read pointer */char* _io_read_end;/* end of Get area. */char* _io_read_base;/* Start of Putback+get area. */char* _io_write_base;/* Start of put area. */char* _io_write_ptr;/* current put pointer. */char* _io_write_end;/* end of put area. */char* _io_buf_base;/* Start of reserve area. */char* _io_buf_end;/* end of reserve area. */* The following fields is used to support backing up and undo. */char *_io_save_base; /* Pointer to start of non-current get area. */char *_io_backup_base; /* Pointer to first valid character of the backup area */char *_io_save_end; /* Pointer to end of Non-current get area. */struct _io_marker *_markers; struct _io_file *_chain; int _fileno; #if 0 int _blksize; #else int _flags2; #endif _i O_o ff_t _old_offset; /* This used to is _offset but it ' s too small. */#define __HAVE_COLUMN/* Temporary */* 1+column number of pbase (); 0 is unknown. */unsigned short _cur_column; Signed Char _vtable_offset; Char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */_io_lock_t *_lock; #ifdef _io_use_old_io_file};
There is a temporary file and memory stream of content, now not to share with you, later encountered in the detailed study it.
On the 6th question of the post-book exercise to share my opinion
The topic is as follows: The printed hint message does not contain a newline character, and the program does not call the Fflush function, what is the reason for explaining the output hint information?
The two-point condition is given in the topic and analyzed by article.
"The printed prompt does not contain a newline character" because standard I/O uses the row buffer mode, so there is no line break to perform I/O operations. Here is not the output of the prompt message.
"The program also does not call the Fflush function", the function of the Fflush function is to transfer all the non-written data of the stream to the kernel. As a special case, if the FP is null, this function will cause all output streams to be purged. Here is not the output of the prompt message.
The result of the above two points is not output prompt information, then what causes the output of the message?
This is based on the feature of row buffering: the input data is obtained from a row buffered stream and the output stream is automatically flushed. This is where the standard output device will flush automatically each time the fgets is called.
We can verify the above content through a few simple experiments. First look at a source that will never output:
#include <stdio.h>int main () {char output[] = "Hello World";p rintf ("%s", output) and while (1); return 0;}
After calling printf, the program goes into a dead loop, and the previous knowledge can be used to understand that when a process terminates gracefully, all standard I/O streams with write buffered data are flushed. The information has not been exported because the process has not terminated normally.
Make a little adjustment for the 1th:
#include <stdio.h>int main () {char output[] = "Hello world\n";p rintf ("%s", output), while (1); return 0;}
At this point the program can output normally, or make the same adjustments:
#include <stdio.h>int main () {char output[] = "Hello World";p rintf ("%s\n", Output) and while (1); return 0;}
All right, after reading 1th, make adjustments for the 2nd:
#include <stdio.h>int main () {char output[] = "Hello World";p rintf ("%s", output); Fflush (stdout); while (1); return 0 ;}
One final adjustment method:
#include <stdio.h>int main () {char output[] = "Hello World";p rintf ("%s", output); fgetc (stdin); while (1); return 0;}
Standard input after standard output.
Apue Reading notes-fifth standard I/O Library