Declarations And Prototypes

From RAD Studio
Jump to: navigation, search

Go Up to Functions Index

In the Kernighan and Ritchie style of declaration, a function could be implicitly declared by its appearance in a function call, or explicitly declared as follows

<type> func();

where type is the optional return type defaulting to int. In C++, this declaration means

<type> func(void);

A function can be declared to return any type except an array or function type. This approach does not allow the compiler to check that the type or number of arguments used in a function call match the declaration.

This problem was eased by the introduction of function prototypes with the following declaration syntax:

<type> func(parameter-declarator-list);

Note: You can enable a warning within the IDE or with the command-line compiler: "Function called without a prototype."

Declarators specify the type of each function parameter. The compiler uses this information to check function calls for validity. The compiler is also able to coerce arguments to the proper type. Suppose you have the following code fragment:

extern long lmax(long v1, long v2); /* prototype */
foo()
{
   int limit = 32;
   char ch = 'A';
   long mval;
   mval = lmax(limit,ch);    /* function call */
}

Since it has the function prototype for lmax, this program converts limit and ch to long, using the standard rules of assignment, before it places them on the stack for the call to lmax. Without the function prototype, limit and ch would have been placed on the stack as an integer and a character, respectively; in that case, the stack passed to lmax would not match in size or content what lmax was expecting, leading to problems. The classic declaration style does not allow any checking of parameter type or number, so using function prototypes aids greatly in tracking down programming errors.

Function prototypes also aid in documenting code. For example, the function strcpy takes two parameters: a source string and a destination string. The question is, which is which? The function prototype

char *strcpy(char *dest, const char *source);

makes it clear. If a header file contains function prototypes, then you can print that file to get most of the information you need for writing programs that call those functions. If you include an identifier in a prototype parameter, it is used only for any later error messages involving that parameter; it has no other effect.

A function declarator with parentheses containing the single word void indicates a function that takes no arguments at all:

func(void);

In C++, func() also declares a function taking no arguments.

A function prototype normally declares a function as accepting a fixed number of parameters. For functions that accept a variable number of parameters (such as printf), a function prototype can end with an ellipsis (...), like this:

f(int *count, long total, ...);

With this form of prototype, the fixed parameters are checked at compile time, and the variable parameters are passed with no type checking.

Note: stdarg.h and varargs.h contain macros that you can use in user-defined functions with variable numbers of parameters.

Here are some more examples of function declarators and prototypes:

int  f();                /* In C, a function returning an int with
                           no information about parameters.
                           This is the K&R "classic style" */
int f();                 /* In C++, a function taking no arguments */
int  f(void);            /* A function returning an int that takes
                           no parameters. */
int  p(int,long);        /* A function returning an int that
                           accepts two parameters:
                           - the first, an int;
                           - the second, a long. */
int  __pascal q(void);   /* A pascal function returning
                          an int that takes no parameters at all. */
int  printf(char *format,...);  /*A function returning an int
                           and accepting a pointer to a char fixed
                           parameter and any number of additional
                           parameters of unknown type. */
int  (*fp)(int);         /* A pointer to a function returning an 
                           int and requiring an int parameter. */