A library in C is merely a group of functions and declarations. The library has an interface expressed in a file with a .h extension and an implementation expressed in a file with a .c extension (which may be precompiled or otherwise inaccessible).
Libraries may call functions in other libraries such as the Standard C or math libraries to do various
tasks.
tasks.
For example, suppose you want to write a function to parse arguments from the command line.
Arguments on the command line could be by themselves:
Arguments on the command line could be by themselves:
i
ioptarg
or have the argument in a separate argvelement:
i optarg
Suppose you want the ability to bunch switches in one argvelement as well. Anyway, after much writing, you come up with this:
#include <stdio.h> /* for fprintf() and EOF */
#include <string.h> /* for strchr() */
/* variables */
int opterr = 1; /* getopt prints errors if this is on */
int optind = 1; /* token pointer */
int optopt; /* option character passed back to user */
char *optarg; /* flag argument (or value) */
/* function */
/* return option character, EOF if no more or ? if problem.
The arguments to the function:
The arguments to the function:
argc, argv the arguments to the main() function. An argument of "" stops the processing.
opts a string containing the valid option characters.
an option character followed by a colon (:) indicates that the option has a required argument.
*/
int
getopt (int argc, char **argv, char *opts)
{
{
static int sp = 1; /* character index into current token */
register char *cp; /* pointer into current token */
if (sp == 1)
{
{
/* check for more flaglike tokens */
if (optind >= argc || argv[optind][0] != '' || argv[optind][1] == '\0')
return EOF;
return EOF;
else if (strcmp (argv[optind], "") == 0)
{
{
optind++;
return EOF;
}
}
optopt = argv[optind][sp];
if (optopt == ':' || (cp = strchr (opts, optopt)) == NULL)
{
{
if (opterr)
fprintf (stderr, "%s: invalid option '%c'\n", argv[0], optopt); /* if no characters left in this token, move to next token */
if (argv[optind][++sp] == '\0')
if (argv[optind][++sp] == '\0')
{
optind++;
sp = 1; }
sp = 1; }
return '?';
}
if (*++cp == ':')
{
{
/* if a value is expected, get it */
if (argv[optind][sp + 1] != '\0')
/* flag value is rest of current token */
optarg = argv[optind++] + (sp + 1);
else if (++optind >= argc)
optarg = argv[optind++] + (sp + 1);
else if (++optind >= argc)
{
if (opterr)
fprintf (stderr, "%s: option requires an argument '%c'\n",
argv[0], optopt);
argv[0], optopt);
sp = 1;
return '?';
}
else
/* flag value is next token */
optarg = argv[optind++];
sp = 1;
optarg = argv[optind++];
sp = 1;
}
else
{
{
/* set up to look at next char in token, next time */ if (argv[optind][++sp] == '\0')
{
/* no more in current token, so setup next token */ sp = 1;
optind++;
}
optarg = 0;
}
return optopt;
}
/* END OF FILE */
The implementation would be the code above. The interface would be the following:
#ifndef GETOPT_H
#define GETOPT_H
/* exported variables */
extern int opterr, optind, optopt; extern char *optarg;
/* exported function */
int getopt(int, char **, char *);
#endif
#endif
/* END OF FILE */
All the programmer that is supposed to use this library sees (if he doesn't want to or can't look at the
implementation) is the interface and the documentation that the library programmer wrote. The
documentation should say that neither pointer can be null (or why would you be using the getopt
implementation) is the interface and the documentation that the library programmer wrote. The
documentation should say that neither pointer can be null (or why would you be using the getopt
uses this library is not interested in the implementation of the library (unless the implementation has
a bug, in which case he would want to complain somehow
Introduction
The stdio.h header declares a broad assortment of functions that perform input and output to
files and devices such as the console. It was one of the earliest headers to appear in the C library. It declares more functions than any other standard header and also requires more explanation because of the complex machinery that underlies the functions.
The deviceindependent model of input and output has seen dramatic improvement over the years
and has received little recognition for its success. FORTRAN II was touted as a machine
independent language in the 1960s, yet it was essentially impossible to move a FORTRAN program
between architectures without some change. In FORTRAN II, you named the device you were
talking to right in the FORTRAN statement in the middle of your FORTRAN code. So, you said
READ INPUT TAPE 5 on a tapeoriented IBM 7090 but READ CARD to read a card image on
other machines. FORTRAN IV had more generic READ and WRITE statements, specifying a
logical unit number (LUN) instead of the device name. The era of deviceindependent I/O had
dawned.
and has received little recognition for its success. FORTRAN II was touted as a machine
independent language in the 1960s, yet it was essentially impossible to move a FORTRAN program
between architectures without some change. In FORTRAN II, you named the device you were
talking to right in the FORTRAN statement in the middle of your FORTRAN code. So, you said
READ INPUT TAPE 5 on a tapeoriented IBM 7090 but READ CARD to read a card image on
other machines. FORTRAN IV had more generic READ and WRITE statements, specifying a
logical unit number (LUN) instead of the device name. The era of deviceindependent I/O had
dawned.
Peripheral devices such as printers still had fairly strong notions about what they were asked to do. And then, peripheral interchange utilities were invented to handle bizarre devices. When cathode ray tubes came onto the scene, each manufacturer of consoles solved problems such as console cursor movement in an independent manner, causing further headaches.
It was into this atmosphere that Unix was born. Ken Thompson and Dennis Ritchie, the developers of Unix, deserve credit for packing any number of bright ideas into the operating system. Their approach to device independence was one of the brightest.
The ANSI C <stdio.h> library is based on the original Unix file I/O primitives but casts a wider net to accommodate the leastcommon denominator across varied systems.
Streams
Input and output, whether to or from physical devices such as terminals and tape drives, or whether to or from files supported on structured storage devices, are mapped into logical data streams,
whose properties are more uniform than their various inputs and outputs. Two forms of mapping are supported: text streams and binary streams.
whose properties are more uniform than their various inputs and outputs. Two forms of mapping are supported: text streams and binary streams.
A text stream is an ordered sequence of characters composed into lines, each line consisting of zero
or more characters plus a terminating newline character. Whether the last line requires a
terminating newline character is implementationdefined. Characters may have to be added, altered,
or deleted on input and output to conform to differing conventions for representing text characters in
a stream and those in the external representation. Data read in from a text stream will necessarily
compare equal to the data that were earlier written out to that stream only if the data consist only of
printable characters and the control characters horizontal tab and newline, no newline character is
immediately preceded by space characters, and the last character is a newline character. Whether
space characters that are written out immediately before a newline character appear when read in is
implementationdefined.
or deleted on input and output to conform to differing conventions for representing text characters in
a stream and those in the external representation. Data read in from a text stream will necessarily
compare equal to the data that were earlier written out to that stream only if the data consist only of
printable characters and the control characters horizontal tab and newline, no newline character is
immediately preceded by space characters, and the last character is a newline character. Whether
space characters that are written out immediately before a newline character appear when read in is
implementationdefined.
Unix adopted a standard internal format for all text streams. Each line of text is terminated by a
newline character. That's what any program expects when it reads text, and that's what any program
produces when it writes text. If such a convention doesn't meet the needs of a textoriented
peripheral attached to a Unix machine, then the fixup occurs out at the edges of the system. None of the code in the middle needs to change.
peripheral attached to a Unix machine, then the fixup occurs out at the edges of the system. None of the code in the middle needs to change.
A binary stream is an ordered sequence of characters that can transparently record internal data. Data read in from a binary stream shall compare equal to the data that were earlier written out to that stream under the same implementation. Such a stream may, however, have an implementation defined number of null characters appended to the end of the stream.
Nothing in Unix prevents the program from writing arbitrary 8bit binary codes to any open file, or reading them back unchanged from an adequate repository. Thus, Unix obliterated the longstanding distinction between text streams and binary streams.
FILE pointers
The <stdio.h> header contains a definition for a type FILE (usually via a typedef) which is
capable of recording all the information needed to control a stream, including its file position
indicator, a pointer to the associated buffer (if any), an error indicator that records whether a
read/write error has occurred, and an endoffile indicator that records whether the end of the file
has been reached.
capable of recording all the information needed to control a stream, including its file position
indicator, a pointer to the associated buffer (if any), an error indicator that records whether a
read/write error has occurred, and an endoffile indicator that records whether the end of the file
has been reached.
It is considered bad manners to access the contents of FILE directly unless the programmer is
writing an implementation of <stdio.h> and its contents. How, pray tell, is one going to know whether the file handle, for example, is spelt handle or _Handle? Access to the contents of FILE is better provided via the functions in <stdio.h>.
Opening and Closing Files
To open and close files, the <stdio.h> library has three functions: fopen, freopen, and fclose.
Opening Files
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
FILE *freopen(const char *filename, const char *mode, FILE *stream);
The fopen and freopen functions open files.
The fopen function opens the file whose name is in the string pointed to by filename and
associates a stream with it.
The argument mode points to a string beginning with one of the following sequences:
r open a text file for reading
w truncate to zero length or create a text file for writing
a append; open or create text file for writing at endoffile
rb open binary file for reading
wb truncate to zero length or create a binary file for writing
ab append; open or create binary file for writing at endoffile
r+ open text file for update (reading and writing)
w+ truncate to zero length or create a text file for update
a+ append; open or create text file for update
r+b or rb+ open binary file for update (reading and writing)
w+b or wb+ truncate to zero length or create a binary file for update a+b or ab+ append; open or create binary file for update
Opening a file with read mode ('r' as the first character in the mode argument) fails if the file does not exist or cannot be read.
Opening a file with append mode ('a' as the first character in the mode argument) causes all
subsequent writes to the file to be forced to the thencurrent endoffile, regardless of intervening
calls to the fseek function. In some implementations, opening a binary file with append mode ('b'
as the second or third character in the above list of mode arguments) may initially position the file
position indicator for the stream beyond the last data written, because of null character padding.
calls to the fseek function. In some implementations, opening a binary file with append mode ('b'
as the second or third character in the above list of mode arguments) may initially position the file
position indicator for the stream beyond the last data written, because of null character padding.
When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream.
However, output may not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input may not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters endoffile. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations.
However, output may not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input may not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters endoffile. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations.
When opened, a stream is fully buffered if and only if it can be determined not to refer to an interactive device. The error and endoffile indicators are cleared.
The fopen function returns a pointer to the object controlling the stream. If the open operation fails, fopen returns a null pointer.
The freopen function opens the file whose name is the string pointed to by filename and associates the stream pointed to by stream with it. The mode argument is used just as in the fopen function.
The freopen function first attempts to close any file that is associated with the specified stream.
Failure to close the file successfully is ignored. The error and endoffile indicators for the stream
are cleared.
Failure to close the file successfully is ignored. The error and endoffile indicators for the stream
are cleared.
The freopen function returns a null pointer if the open operation fails, or the value stream if the open operation succeeds.
Closing Files
#include <stdio.h>
int fclose(FILE *stream);
The fclose function causes the stream pointed to by stream to be flushed and the associated file
to be closed. Any unwritten buffered data for the stream are delivered to the host environment to be
written to the file; any unread buffered data are discarded. The stream is disassociated from the file.
to be closed. Any unwritten buffered data for the stream are delivered to the host environment to be
written to the file; any unread buffered data are discarded. The stream is disassociated from the file.
If the associated buffer was automatically allocated, it is deallocated. The function returns zero if the stream was successfully closed or EOF if any errors were detected.
Other file access functions
The fflush function
#include <stdio.h>
int fflush(FILE *stream);
If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be deferred to the host environment to be written to the file; otherwise, the behavior is undefined.
If stream is a null pointer, the fflush function performs this flushing action on all streams for which the behavior is defined above.
The fflush functions returns EOF if a write error occurs, otherwise zero.
The reason for having a fflush function is because streams in C can have buffered input/output; that is, functions that write to a file actually write to a buffer inside the FILE structure. If the buffer is filled to capacity, the write functions will call fflush to actually "write" the data that is in the buffer to the file. Because fflush is only called every once in a while, calls to the operating
system to do a raw write are minimized.
system to do a raw write are minimized.
The setbuf function
#include <stdio.h>
void setbuf(FILE *stream, char *buf);
Except that it returns no value, the setbuf function is equivalent to the setvbuf function
invoked with the values _IOFBF for mode and BUFSIZ for size, or (if buf is a null pointer) with the value _IONBF for mode.
The setvbuf function
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
The setvbuf function may be used only after the stream pointed to by stream has been
associated with an open file and before any other operation is performed on the stream. The
argument mode determines how the stream will be buffered, as follows: _IOFBF causes
input/output to be fully buffered; _IOLBF causes input/output to be line buffered; _IONBF causes input/output to be unbuffered. If buf is not a null pointer, the array it points to may be used instead of a buffer associated by the setvbuf function. (The buffer must have a lifetime at least as great as the open stream, so the stream should be closed before a buffer that has automatic storage duration is deallocated upon block exit.) The argument size specifies the size of the array. The contents of the array at any time are indeterminate.
The setvbuf function returns zero on success, or nonzero if an invalid value is given for mode or if the request cannot be honored.
Functions that Modify the File Position Indicator
The stdio.h library has five functions that affect the file position indicator besides those that do reading or writing: fgetpos, fseek, fsetpos, ftell, and rewind.
The fseek and ftell functions are older than fgetpos and fsetpos.
The fgetpos and fsetpos functions
#include <stdio.h>
int fgetpos(FILE *stream, fpos_t *pos);
int fsetpos(FILE *stream, const fpos_t *pos);
The fgetpos function stores the current value of the file position indicator for the stream pointed to by stream in the object pointed to by pos. The value stored contains unspecified information
usable by the fsetpos function for repositioning the stream to its position at the time of the call to the fgetpos function.
usable by the fsetpos function for repositioning the stream to its position at the time of the call to the fgetpos function.
If successful, the fgetpos function returns zero; on failure, the fgetpos function returns nonzero and stores an implementationdefined positive value in errno.
The fsetpos function sets the file position indicator for the stream pointed to by stream
according to the value of the object pointed to by pos, which shall be a value obtained from an earlier call to the fgetpos function on the same stream.
A successful call to the fsetpos function clears the endoffile indicator for the stream and
undoes any effects of the ungetc function on the same stream. After an fsetpos call, the next operation on an update stream may be either input or output.
If successful, the fsetpos function returns zero; on failure, the fsetpos function returns nonzero and stores an implementationdefined positive value in errno.
The fseek and ftell functions
#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence); long int ftell(FILE *stream);
The fseek function sets the file position indicator for the stream pointed to by stream.
For a binary stream, the new position, measured in characters from the beginning of the file, is
obtained by adding offset to the position specified by whence. Three macros in stdio.h
called SEEK_SET, SEEK_CUR, and SEEK_END expand to unique values. If the position specified by whence is SEEK_SET, the specified position is the beginning of the file; if whence is
SEEK_END, the specified position is the end of the file; and if whence is SEEK_CUR, the
specified position is the current file position. A binary stream need not meaningfully support
fseek calls with a whence value of SEEK_END.
SEEK_END, the specified position is the end of the file; and if whence is SEEK_CUR, the
specified position is the current file position. A binary stream need not meaningfully support
fseek calls with a whence value of SEEK_END.
For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier call to the ftell function on the same stream and whence shall be SEEK_SET.
The fseek function returns nonzero only for a request that cannot be satisfied.
The ftell function obtains the current value of the file position indicator for the stream pointed to
by stream. For a binary stream, the value is the number of characters from the beginning of the
file; for a text stream, its file position indicator contains unspecified information, usable by the
fseek function for returning the file position indicator for the stream to its position at the time of
by stream. For a binary stream, the value is the number of characters from the beginning of the
file; for a text stream, its file position indicator contains unspecified information, usable by the
fseek function for returning the file position indicator for the stream to its position at the time of
the ftell call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read.
If successful, the ftell function returns the current value of the file position indicator for the
stream. On failure, the ftell function returns 1L and stores an implementationdefined positive value in errno.
The rewind function
#include <stdio.h>
void rewind(FILE *stream);
The rewind function sets the file position indicator for the stream pointed to by stream to the beginning of the file. It is equivalent to
(void)fseek(stream, 0L, SEEK_SET)
except that the error indicator for the stream is also cleared.
Error Handling Functions
The clearerr function
#include <stdio.h>
void clearerr(FILE *stream);
The clearerr function clears the endoffile and error indicators for the stream pointed to by stream.
The feof function
#include <stdio.h>
int feof(FILE *stream);
The feof function tests the endoffile indicator for the stream pointed to by stream and returns nonzero if and only if the endoffile indicator is set for stream, otherwise it returns zero.
The ferror function
#include <stdio.h>
int ferror(FILE *stream);
The ferror function tests the error indicator for the stream pointed to by stream and returns nonzero if and only if the error indicator is set for stream, otherwise it returns zero.
The perror function
#include <stdio.h>
void perror(const char *s);
The perror function maps the error number in the integer expression errno to an error message.
It writes a sequence of characters to the standard error stream thus: first, if s is not a null pointer
and the character pointed to by s is not the null character, the string pointed to by s followed by a
It writes a sequence of characters to the standard error stream thus: first, if s is not a null pointer
and the character pointed to by s is not the null character, the string pointed to by s followed by a
colon (:) and a space; then an appropriate error message string followed by a newline character. The contents of the error message are the same as those returned by the strerror function with the argument errno, which are implementationdefined.
Other Operations on Files
The stdio.h library has a variety of functions that do some operation on files besides reading and
writing.
writing.
The remove function
#include <stdio.h>
int remove(const char *filename);
The remove function causes the file whose name is the string pointed to by filename to be no longer accessible by that name. A subsequent attempt to open that file using that name will fail, unless it is created anew. If the file is open, the behavior of the remove function is
implementationdefined.
implementationdefined.
The remove function returns zero if the operation succeeds, nonzero if it fails.
The rename function
#include <stdio.h>
int rename(const char *old_filename, const char *new_filename);
The rename function causes the file whose name is the string pointed to by old_filename to
be henceforth known by the name given by the string pointed to by new_filename. The file
named old_filename is no longer accessible by that name. If a file named by the string pointed to by new_filename exists prior to the call to the rename function, the behavior is
implementationdefined.
be henceforth known by the name given by the string pointed to by new_filename. The file
named old_filename is no longer accessible by that name. If a file named by the string pointed to by new_filename exists prior to the call to the rename function, the behavior is
implementationdefined.
The rename function returns zero if the operation succeeds, nonzero if it fails, in which case if the file existed previously it is still known by its original name.
The tmpfile function
#include <stdio.h>
FILE *tmpfile(void);
The tmpfile function creates a temporary binary file that will automatically be removed when it
is closed or at program termination. If the program terminates abnormally, whether an open
temporary file is removed is implementationdefined. The file is opened for update with "wb+"
mode.
is closed or at program termination. If the program terminates abnormally, whether an open
temporary file is removed is implementationdefined. The file is opened for update with "wb+"
mode.
The tmpfile function returns a pointer to the stream of the file that it created. If the file cannot be created, the tmpfile function returns a null pointer.
The tmpnam function
#include <stdio.h>
char *tmpnam(char *s);
The tmpnam function generates a string that is a valid file name and that is not the name of an
existing file.
The tmpnam function generates a different string each time it is called, up to TMP_MAX times.
(TMP_MAX is a macro defined in stdio.h.) If it is called more than TMP_MAX times, the behavior is implementationdefined.
The implementation shall behave as if no library function calls the tmpnam function.
If the argument is a null pointer, the tmpnam function leaves its result in an internal static object and returns a pointer to that object. Subsequent calls to the tmpnam function may modify the same object. If the argument is not a null pointer, it is assumed to point to an array of at least L_tmpnam characters (L_tmpnam is another macro in stdio.h); the tmpnam function writes its result in that array and returns the argument as its value.
The value of the macro TMP_MAX must be at least 25.
0 comments:
Post a Comment