Including Function Declarations

The run-time library header files also contain function declarations for every function in the run-time library. These declarations are in the style recommended by the ANSI C standard. Given these declarations, the compiler can perform “type checking” on every reference to a library function, making sure that you have used the correct return type and arguments. Function declarations are sometimes called “prototypes,” since the declaration serves as a prototype or template for every subsequent reference to the function.

A function declaration lists the name of the function, its return type, and the number and type of its arguments. For instance, this is the declaration of the pow library function from the header file MATH.H:

double pow( double x, double y );

The example declares that pow returns a value of type double and takes two arguments of type double. Given this declaration, the compiler can check every reference to pow in your program to ensure that the reference passes two double arguments to pow and takes a return value of type double.

The compiler can perform type checking only for function references that appear after the function declaration. Because of this, function declarations normally appear near the beginning of the source file, prior to any use of the functions they declare.

Function declarations are especially important for functions that return a value of some type other than int, which is the default. For example, the pow function returns a double value. If you do not declare such a function, the compiler treats its return value as int, which can cause unexpected results.

It is also a good practice to provide declarations for functions that you write. If you do not want to type the declarations by hand, you can generate them automatically by using the /Zg compiler option. This option causes the compiler to generate ANSI-standard function declarations for every function defined in the current source file. Redirect this output to a file, then insert the file near the beginning of your source file.

Your program can contain more than one declaration of the same function, as long as the declarations do not conflict. This is important if you have old programs whose function declarations do not contain argument-type lists. For instance, if your program contains the declaration

char *calloc( );

you can later include the following declaration:

char *calloc(unsigned, unsigned);

Because the two declarations are compatible, even though they are not identical, no conflict occurs. The second declaration simply gives more information about function arguments than the first. A conflict would arise, however, if the declarations gave a different number of arguments or gave arguments of different types.

Some library functions can take a variable number of arguments. For instance, the printf function can take one argument or several. The compiler can perform only limited type checking on such functions, a factor that affects the following library functions:

In calls to _cprintf, _cscanf, printf, and scanf, only the first argument (the format string) is type checked.

In calls to fprintf, fscanf, _snprintf, sprintf, and sscanf, only the first two arguments (the file or buffer and the format string) are type checked.

In calls to _open, only the first two arguments (the path name and the _open flag) are type checked.

In calls to _sopen, only the first three arguments (the path name, the _open flag, and the sharing mode) are type checked.

In calls to _execl, _execle, _execlp, and _execlpe, only the first two arguments (the path name and the first argument pointer) are type checked.

In calls to _spawnl, _spawnle, _spawnlp, and _spawnlpe, only the first three arguments (the mode flag, the path name, and the first argument pointer) are type checked.