9.1. Introduction

There is no doubt that the Standard Committee's decision to define a set of library routines will prove to be a huge benefit to users of C. Previously there were no standard, accepted, definitions of library routines to provide support for the language. As a result, portability suffered seriously.

The library routines do not have to be present; they will only be present in a hosted environment—typically the case for applications programmers. Writers of embedded systems and the writers of the hosted environment libraries will not have the libraries present. They are using ‘raw’ C, in a freestanding environment, and this chapter will not be of much interest to them.

The descriptions (except for this introduction) are not meant to be read as a whole chapter, but as individual pieces. The material included here is meant more for information and convenient reference than as a full tutorial introduction. It would take a full book by itself to do real justice to the libraries.

9.1.1. Headers and standard types

A number of types and macros are used widely by the library functions. Where necessary, they are defined in the appropriate #include file for that function. The header will also declare appropriate types and prototypes for the library functions. Some important points should be noted here:

The Standard isn't quite as restrictive about identifiers as the list above is, but it's a brave move to make use of the loopholes. Play safe instead.

The Standard headers are:

<assert.h>   <locale.h>   <stddef.h>
<ctype.h>    <math.h>     <stdio.h>
<errno.h>    <setjmp.h>   <stdlib.h>
<float.h>    <signal.h>   <string.h>
<limits.h>   <stdarg.h>   <time.h>

A last general point is that many of the library routines may be implemented as macros, provided that there will be no problems to do with side-effects (as Chapter 7 describes). The Standard guarantees that, if a function is normally implemented as a macro, there will also be a true function provided to do the same job. To use the real function, either undefine the macro name with #undef, or enclose its name in parentheses, which ensures that it won't be treated as a macro:

some function("Might be a macro\n");
(some function)("Can't be a macro\n");

9.1.2. Character set and cultural dependencies

The Committee has introduced features that attempt to cater for the use of C in environments which are not based on the character set of US ASCII and where there are cultural dependencies such as the use of comma or full stop to indicate the decimal point. Facilities have been provided (see Section 9.4) for setting a program's idea of its locale, which is used to control the behaviour of the library functions.

Providing full support for different native languages and customs is a difficult and poorly understood task; the facilities provided by the C library are only a first step on the road to a full solution.

In several places the ‘C locale’ is referred to. This is the only locale defined by the Standard and effectively provides support for the way that Old C worked. Other locale settings may provide different behaviour in implementation-defined ways.

9.1.3. The <stddef.h> Header

There are a small number of types and macros, found in <stddef.h>, which are widely used in other headers. They are described in the following paragraphs.

Subtracting one pointer from another gives a result whose type differs between different implementations. To allow safe use of the difference, the type is defined in <stddef.h> to be ptrdiff_t. Similarly, you can use size_t to store the result of sizeof.

For reasons which still escape us, there is an ‘implementation defined null pointer constant’ defined in <stddef.h> called NULL. Since the language explicitly defines the integer constant 0 to be the value which can be assigned to, and compared with, a null pointer, this would seem to be unnecessary. However, it is very common practice among experienced C programmers to write this sort of thing:

#include <stdio.h>
#include <stddef.h>
FILE *fp;

if((fp = fopen("somefile", "r")) != NULL){
        /* and so on */

There is also a macro called offsetof which can be used to find the offset, in bytes, of a structure member. The offset is the distance between the member and the start of the structure. It would be used like this:

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

        size_t distance;
        struct x{
                int a, b, c;

        distance = offsetof(s_tr, c);
        printf("Offset of x.c is %lu bytes\n",
                (unsigned long)distance);

Example 9.1

The expression s_tr.c must be capable of evaluation as an address constant (see Chapter 6). If the member whose offset you want is a bitfield, then you're out of luck; offsetof has undefined behaviour in that case.

Note carefully the way that a size_t has to be cast to the longest possible unsigned type to ensure that not only is the argument to printf of the type that it expects (%luis the format string for unsigned long), but also no precision is lost. This is all because the type of size_t is not known to the programmer.

The last item declared in <stddef.h> is wchar_t, an integral type large enough to hold a wide character from any supported extended character sets.

9.1.4. The <errno.h> Header

This header defines errno along with the macros EDOM and ERANGE, which expand to nonzero integral constant expressions; their form is additionally guaranteed to be acceptable to #if directives. The latter two are used by the mathematical functions to report which kind of errors they encountered and are more fully described later.

errno is provided to tell you when library functions have detected an error. It is not necessarily, as it used to be, an external variable, but is now a modifiable lvalue that has type int. It is set to zero at program start-up, but from then on never reset unless explicitly assigned to; in particular, the library routines never reset it. If an error occurs in a library routine, errno is set to a particular value to indicate what went wrong, and the routine returns a value (often −1) to indicate that it failed. The usual use is like this:

#include <stdio.h>
#include <stddef.h>
#include <errno.h>

errno = 0;
if(some_library_function(arguments) < 0){
        /* error processing code... */
        /* may use value of errno directly */

The implementation of errno is not known to the programmer, so don't try to do anything other than reset it or inspect its value. It isn't guaranteed to have an address, for example.

What's more, you should only check errno if the particular library function in use documents its effect on errno.

Other library functions are free to set it to arbitrary values after a call unless their description explicitly states what they do with it.