Mechanics




Document: The C Standard Library

next Implementation-defined Limits: limits.h
up The C Standard Library
gif On Re-inventing Wheels

Mechanics

In order to use the facilities of the Standard Library, one must have some understanding of the mechanics of how the compiler will access it.

Some very simple C programs can be completely "self-contained": all the code for all the functions was contained in a single program file. In general, however, this need not be the case; in particular, it will not be the case if you wish to make use of the Standard Library.

In principle, of course, the Standard Library could be distributed simply as a set of one or more C source code files. You would then use a library function simply by copying the source code out of the relevant library file and pasting it into your own program file. However, this is not the mechanism which is used in practise for a variety of reasons:

What is actually done is that the Standard Library software is distributed in a sort of "canned" or precompiled form, as a set of "object files" (or, more commonly, a single "object library" file). Your program file(s) are then compiled completely separately from the source code for the Standard Library, yielding one or more further object files. Finally, all the required "object" files, both your own, and those making up the Standard Library, are combined or linked together to yield the "executable" file, which can actually be run.

To a large extent this process can be made automatic and invisible. The compiler compiles your source file(s) to the "object" code form, and then automatically links these together with the any required library object file(s).

However, it cannot be made completely automatic. In practise there is certain information, associated with the Standard Library, which the compiler must be made aware of at the time it is compiling your source files, in order to make sure that the object files produced will correctly link up with the object files for the Standard Library.

Since, for the most part, the Standard Library simply consists of a set of functions which you can call in your program, the most important such information is the way data is to be exchanged with each such function; i.e. how many parameters does the function take, of what types, in what order, and what type of return value does the function yield (if any)?

The compiler could, of course, try to infer this information from the way the function is actually called; but this is not always technically possible, and, in any case, it is much better if the compiler has some independent way of knowing how the function should be called, because then it can automatically check whether you have, in each case, called it correctly. It turns out that this is extremely useful, and is an effective way of automatically detecting a range of very common programming mistakes.

The compiler is given this information about how a function should be called by the use of a so-called function prototype. This is simply the "header" of the function definition, which states the function name, the return type, and the formal parameter list. But whereas, in a function definition this is then followed by a compound statement which actually defines the function, in a function prototype it is simply followed by a terminating semicolon. Thus, a prototype might look like this for example:

    int multiply(unsigned *multiplicand,
      unsigned multiplier, unsigned *product);

This tells the compiler that the function called multiply should take three parameters, respectively of types (unsigned *), unsigned and (unsigned *), and will yield a return value of type int. Function prototypes should appear at the outermost level of a source file - i.e. not within the definition of any function.

So far, so good. It seems that if you wish to call or invoke any of the Standard Library functions in your program,, you must simply insert, somewhere before the function(s) which make such call(s), a suitable function prototype, so that the compiler will then be able to decide whether the calls are correct or not.

But how are you going to know what is the correct prototype for each function in the first place?

Well, one possibility is to look up the function in the detailed technical documentation for the Standard Library: this will normally include the function prototype. You can then copy that into your own file.

However, this is clearly unsatisfactory. Apart from being laborious, it is error prone - and the possibility of an error in the function prototype undermines a primary point of using prototypes in the first place, namely that it allows the compiler to crosscheck for valid function calls! A better idea is if the prototypes are provided to you in a machine readable form - i.e. in one or more files on the computer. Then you can simply copy the required ones, and paste them into your own source files.

Well, yes, this is a major improvement, but still leaves something to be desired. For one thing, duplicating the prototypes in every source program wastes disk space. More seriously, there is always a danger that you might (accidentally) modify a prototype, again confounding the idea of allowing the compiler to automatically crosscheck the prototype against the invocation(s) of the function.

A final possibility is to leave the prototypes in one or more separate files; but have the compiler automatically access or scan the relevant files immediately before, or as part of the process of, compiling your files. In this way, there is no laborious, manual, copying of the prototypes, but no duplication and no risk of accidental modification either.

Files which are used for this kind of purpose - which contain no actual executable code, but which contain only function prototypes (and possibly other things such as symbolic constants etc.) which allow the compiler to correctly mesh the file it is compiling with some other software which has been "pre-compiled", are called header files. Header files are normally given the extension .h to distinguish them from files which actually contain executable code - function definitions etc. - which will normally have the extension .c .

It would be possible, in principle, to put all the prototypes for all the functions in the Standard Library, plus any other required information (symbolic constants etc.), in a single .h file, and have the compiler automatically include it in compiling any file. However, in practise this is not done for various reasons. For example, most .c files only involve calling a small subset of the functions in the Standard Library; it is then wasteful and time consuming for the compiler to process prototypes for all functions in the Standard Library.

The mechanism that is actually used then is as follows. A series of separate .h files are supplied with the compiler. Each one provides prototypes (plus other required information) relating to only some coherent or related subset of the functions in the Standard Library. The programmer must then explicitly instruct the compiler to process just those .h files which are required in order to properly compile any particular .c file. And this is done by inserting, into the .c file one or more so-called #include directives. A #include directive is something much the same as a #define in the sense that it is not handled by the compiler "proper" but by the "pre-processor" which runs (automatically) immediately before the compiler. In this case, the pre-processor processes a #include by concatenating together the .h file and the original .c file, to produce a big temporary file which is what is actually then processed in the compilation phase proper.

Thus, if you want to use a function from the Standard Library, you must first look up, in the relevant technical documentation, which header file contains the prototype etc. for that function; and then insert a line something like the following in your .c file:

        #include <stdio.h>

The angle brackets around the name of the header file tell the pre-processor to search for the file in the "standard" directories for such things; normally these will be set up when the compiler is installed, and you, as a programmer, need not worry about what these standard directories actually are.

You may, of course, need to #include several header files, depending on the particular selection of Standard Library functions you wish to use.

All required #include directives are normally placed close to the top of your .c file - typically either at the very top, or immediately after an initial introductory comment which documents the overall contents of the source file. Each #include must, in any case, precede any calls or invocations of the relevant functions.

The rest of this essay is concerned with introducing just a very small selection of the several hundred functions normally available in the Standard Library. It is organised into sections according to the distinct .h files required.




Document: The C Standard Library

next Implementation-defined Limits: limits.h
up The C Standard Library
gif On Re-inventing Wheels



McMullin@eeng.dcu.ie
Fri Mar 29 14:35:38 GMT 1996