Other library files do not seem to have any implementation knowledge to explore. Therefore, let's look at stdio. h, stdlib. h, string. h.
1. Miscellaneous, interesting history
Over the past few decades, input and output models independent of devices have developed rapidly, and standard C has benefited a lot from this improved model.
Input and Output modules
In the early 1960s S, fortran iv was considered a machine-independent language. However, without any changes, it is impossible to move the fortran iv program in various computer architectures. The main obstacle to portability is the field of input and output. In fortran iv, you can name the devices that are communicating in the I/O statement in the center of the FORTRAN IV code. CARD and input tape are different.
Later, the logic unit number (LUN) is gradually used to replace the specific device name, so as to add the control card before the executable binary card, this allows you to specify the devices that correspond to a specific LUN during a special running process. At this time, the I/O era independent of devices is approaching.
The further improvement of device independence benefits from advances in the standard peripheral swapping program (PIP. This program allows you to specify any combination of the source device and the target device, and then try to copy between the two devices.
Enter UNIX. UNIX uses the standard internal form for all text streams. Each line of the text is terminated with a line break. This is exactly what the program expects when reading the text, and is also generated by the program output. If such a convention cannot meet the requirements of peripheral devices that are connected to UNIX machines for text processing, some modifications can be made to the external interface of the system without having to modify any internal code. UNIX provides two mechanisms to modify the text stream of the "external interface. The first is a general ing function, which can process device work with any text. You can call ioctl to set or test the parameters of a specific device. Another mechanism for correcting text streams is to modify the specialized software that directly controls the device. For every UNIX device that may need to be controlled, you must add a UNIX-resident Device Manager.
When the first C compiler runs on the UNIX platform, the C language naturally inherits the simple I/O model of its host operating system. In addition to the unified representation of text streams, there are other advantages. The LUNs used a long time ago has gradually evolved into a very small positive integer called a file descriptor or handle in recent decades. The operating system is responsible for distributing file descriptors. In addition, all file control information is stored in your own dedicated memory, rather than allowing users to allocate and maintain file and record control blocks to increase the burden.
To simplify the operation management of most programs, the UNIX shell assigns three standard file descriptors to each running program, which are standard input, standard output, and standard error streams currently used. (Text Stream)
UNIX does not prevent writing arbitrary binary code to any opened files, or read them from a large enough place without changing the way they are. (Binary stream)
Therefore, UNIX eliminates the difference between text streams (communicating with people) and binary streams (communicating with machines.
In the same implementation, the data read from a binary stream should be the same as the data written to this liu, while the text stream is not.
For more information about text streams and binary streams, see http://www.embedu.org/column/column186.htm.
PS: stream is a highly abstract concept at the operating system level, which hides the specific essence of the I/O device, all the data changes brought about by I/O are seen as the inbound and outbound input. In this way, the program simulates various I/O devices into a stream style at the operating system level, the I/O module is abstracted independently. We can see that the process of I/O model development is the process of gradually abstracting and unifying it, which is similar to the process of language development.
The X3J11 Committee began its meeting on 1983 to draft ANSI standards for C. The C vendors of non-UNIX systems have been arguing with those UNIX users for a long time, because UNIX users cannot understand why I/O is so troublesome (apparently, the UNIX file structure and device management mechanism ensure the simplicity of the I/O module, which is an advantage over other operating systems ). This is a very educational process. One of the important by-products of these arguments is to clarify more clearly the I/O Modules supported by C.
Finally, the Board decided to discard UNIX-style primitives after discussing the importance of cleanliness and the importance of backward compatibility. (Mainly balancing code efficiency and code conciseness)
2. Do not know the contents of Lu Shan zhenji.
Type:
FILE is an object type that records all information required by the control flow, including its FILE locator and pointing to the relevant buffer (if any) the pointer of the file, the prompt indicating whether a read/write error has occurred, and the end of the file that records the end of the file (The address of the FILE object used for control flow may be very important. You do not need to use a copy of the FILE object to replace the original object for service.)
There are two types of functions in the Library:
1. Operations on any stream;
2. Specify the operations for the specific file stream;
The two features read/write, file location, buffer control, and other operations to complete all-round flow operations, as long as you can think.
3. Don't worry about the cloudmonitor.
Two design decisions are critical to the implementation of <stdio. h>:
- Data structure FILE content
- Low-level primitives that interact with the operating system to execute actual input/output
Type FILE:
Certificate ------------------------------------------------------------------------------------------------------------------------------------------------------------
(This is for personal understanding, not for original books)
Whether it is a binary stream or a text stream, C processes the file as a continuous byte stream. The information of the byte stream and the FILE descriptor corresponding to the FILE must be stored in the FILE type.
typedef *_ptr; _cnt; *_base; _flag; _file; _charbuf; _bufsiz; *_tmpfname;}FILE;
Although I don't know what these variables mean, I can barely guess the implementation of some functions.
1. FOPEN
FILE * _TSCHAR * _TSCHAR * , REG1 FILE * REG2 FILE * _ASSERTE(file != _ASSERTE(*file != _T( _ASSERTE(mode != _ASSERTE(*mode != _T( ((stream = _getstream()) == retval = /* _UNICODE */ retval = /* _UNICODE */ }
The FILE * type variable is obtained through _ getstream. Therefore, we can look at the implementation of _ getstream. However, before reading the implementation of _ getstream (), it is necessary to introduce the management mechanism of IO control blocks (that is, FILE files) in the C Standard Library:
First, there are three special control blocks in the I/O Control Block: standard input, standard output, and standard error stream. The standard input has a limit on the input size.
_INTERNAL_BUFSIZ 4096 _bufin[_INTERNAL_BUFSIZ];
The size of the standard input stream in the C standard library I use is 4096. We can test it with code:
main( s[ ( i = ; i < ; i++ s[i] = scanf( (i = ; i < ; i++ ( s[i] == printf(,i+ }
The input value is 5000. The output value is 4095. There should be an ending sign. Apparently, the strings that exceed _ INTERNAL_BUFSIZ are removed.
In the C standard library, this I/O control block is managed through a FILE array _ iob and a FILE ** pointer. As follows:
Code Block 1:
_NSTREAM_ 512 _IOB_ENTRIES 20 /* _WIN32 */ _NSTREAM_ 128 /* *MUST* match the value under ifdef _DLL! */ /* CRTDLL */ _NSTREAM_ 128 /* _DLL */ _NSTREAM_ 40 /* _MT */ _NSTREAM_ 20
Code Block 2:
FILE _iob[_IOB_ENTRIES] = , _bufin, _IOREAD | _IOYOURBUF, , , NULL, _IOWRT, , , , NULL, _IOWRT, , ,
Code Block 3:
_nstream = /* CRTDLL */ /* CRTDLL */
** _ Piob;
( (__piob = ( **)_calloc_crt( _nstream, ( *) )) === ( (__piob = ( **)_calloc_crt( _nstream, ( *))) == ( i = ; i < _IOB_ENTRIES ; i++= ( *)&_iob[i];
From code block 2, we can see that FILE _ iob [_ IOB_ENTRIES] is a FILE array with three preset FILE types: stdin, stdout, and stderr. Because the number of I/O control blocks on different platforms is at least 20 (from the definition of _ NSTREAM _), _ IOB_ENTRIES is defined as 20, as the first 20 I/O control blocks. The value here is 20, which makes no sense, as long as the array can accommodate the next three preset I/O control blocks, at the same time, it is possible to generate a waste of space (more than 20 may be wasted ).
_ Piob is a two-dimensional pointer of FILE **. It manages a FILE * pointer array to point to the address of the allocated I/O control block, the maximum size of the pointer array is _ NSTREAM _ = 512. You can test this value.
#include <stdlib.h> #include <stdio.h> main( FILE *p[ file_name[ ( i = ; i < ; i++ itoa(i,file_name, p[i] = fopen(file_name, ( i = ; i< ; i++ }
We can see that 509 files are created in the folder, and the preset stdin, stdout, and stderr are exactly 512.
Management Method
Now let's move our eyes back and look at the implementation of _ getstream:
FILE * REG2 FILE *retval = REG1 ( i = ; i < _nstream ; i++ ( __piob[i] != ( !inuse( (FILE * ( inuse( (FILE * /* _MT */ retval = (FILE * ( (__piob[i] = _malloc_crt( (_FILEX) )) != defined (_MT) InitializeCriticalSection( &(((_FILEX *)__piob[i])-> EnterCriticalSection( &(((_FILEX *)__piob[i])-> /* defined (_MT) */ retval = (FILE * ( retval != retval->_flag = retval->_cnt = retval->_tmpfname = retval->_ptr = retval->_base = retval->_file = - /* _WIN32 */ defined (_M_MPPC) || defined (_M_M68K) REG1 FILE *stream = (; stream <= _lastiob; stream++ ( ! stream->_flag = stream->_cnt = stream->_tmpfname = stream->_ptr = stream->_base = stream->_file = - retval = /* defined (_M_MPPC) || defined (_M_M68K) */ /* _WIN32 */ }
Obviously, when the FILE * pointer is still available, allocate a corresponding FILE space for the first idle FILE. The new stream will be included in the management of the entire I/O control block.
OK, let's go back to the fopen function. After we get an unused I/O control block, what we need to do next is to the I/O block, configure according to the set mode. In this case, the _ openfile function is called.
In _ openfile, You need to mark stream. _ flag = streamflag; streamflag uses bits to mark the types of operations currently performed by _ IOREAD and _ IOWRT. Stream. _ file obtains an int-type file Identifier (a file identifier is created through a lower-level open Series function, and determines whether the data stream is a text stream or a binary stream ).
Then, we can get the meanings of the two variables in the FILE.