A “function declaration” establishes the name and return type of a function and may specify the types, formal parameter names, and number of arguments to the function. A function declaration does not define the function body. It simply makes information about the function known to the compiler. This information enables the compiler to check the types of the actual arguments passed in calls to the function. Functions are declared with declarators:
declarator :
pointer opt direct-declarator
direct-declarator : /* A function declarator */
direct-declarator ( parameter-type-list ) /* New-style declarator */
direct-declarator ( identifier-list opt ) /* Old-style declarator */
parameter-type-list :
parameter-list
parameter-list , ...
parameter-list :
parameter-declaration
parameter-list , parameter-declaration
parameter-declaration :
declaration-specifiers declarator /* Named declarator */
declaration-specifiers abstract-declarator opt /* Anonymous declarator */
identifier-list : /* For old-style declarator */
identifier
identifier-list , identifier
declaration-specifiers :
storage-class-specifier declaration-specifiers opt
type-specifier declaration-specifiers opt
type-qualifier declaration-specifiers opt
abstract-declarator : /* Used with anonymous declarators */
pointer
pointer opt direct-abstract-declarator
direct-abstract-declarator :
( abstract-declarator )
direct-abstract-declarator opt [ constant-expression opt ]
direct-abstract-declarator opt ( parameter-type-list opt )
If specified, storage-class-specifier can be either extern or static. Storage-class specifiers are discussed in “Storage Classes”. The type-specifier gives the function's return type, and declarator names the function. If you omit type-specifier from a function declaration, the function is assumed to return a value of type int. The parameter-type-list is described below in “Parameters.”
Other declarators can appear in the same function declaration. These can be other functions returning values of the same type as the function, or declarations of any variables whose type is the same as the function's return type. Each such declaration must be separated from its predecessors and successors by a comma.
A function prototype gives information about the parameters, allowing the compiler to perform type checking and to convert arguments to the type expected by the parameter. The function definition defines the body of the function.
“Parameters” (sometimes called “formal parameters”) describe the actual arguments that can be passed to a function. In a parameter-type list, the parameter declarations establish the number and types of the actual arguments. They can also include identifiers of the formal parameters.
Note:
Identifiers used to name the parameters in the prototype declaration are descriptive only. They go out of scope at the end of the declaration. Therefore, they need not be identical to the identifiers used in the declaration portion of the function definition. Using the same names may enhance readability but has no other significance.
Although the parameters may be omitted from a function declaration in the optional identifier-list form of the syntax, their inclusion is recommended. The extent of the information in the declaration influences the argument checking done on function calls that appear before the compiler has processed the function definition.
If a function has no parameters, the parentheses should contain the keyword void to specify that no arguments are passed to the function.
The only explicit storage-class-specifier permitted in parameters is register. If register is not specified, the storage class is auto. The register specifier is ignored unless the function declarator has a function definition. If the parentheses contain only the register keyword, the parameter is considered to represent an unnamed int for which register storage is being requested.
The declarator for a pointer, array, or function can be formed by combining a type specifier, plus the appropriate type qualifier, with an identifier. Alternatively, an abstract-declarator (that is, a declarator without a specified identifier) can be used. Complete declarators ( int a ) and abstract declarators ( int ) are permitted in the same prototype. For example:
int func( int a, int ); /* Accepted */
In a parameter declaration, a single typedef name inside parentheses is assumed to be an abstract declarator specifying a function with a single parameter, not as redundant parentheses around an identifier for the declarator. See topic for information about abstract declarators.
One other special construction permitted as a parameter is void *, representing a pointer to an identifier of unspecified type. Thus, in a call, the pointer can be used to pass any type of identifier after you convert the pointer (for example, with a cast) to a pointer to the desired type. Note that before operations can be performed on the pointer or the identifier it addresses, the pointer must be explicitly converted. “Pointer Declarations” provides further information on void *.
The list of parameters can be empty, full, or partial. If the list contains at least one declarator, a variable number of parameters can be specified by ending the list with a comma followed by three periods (, ...), referred to as the “ellipsis notation.” No information about the number or type of the parameters after the comma is supplied. See “Calls with a Variable Number of Arguments” for information about functions with variable numbers of arguments.
Microsoft Specific
To maintain compatibility with previous versions of the Microsoft C compiler, the version 7.0 compiler accepts a comma without trailing periods at the end of a declarator list to indicate a variable number of arguments. (Trailing periods without a comma are not allowed.) However, this is a Microsoft extension to the ANSI C standard. New code should use the comma followed by three periods. ANSI also requires at least one argument before the ellipsis. The STDARG.H file enforces this restriction for accessing arguments.¨Return Types
Functions can return values of any type except arrays and functions. Therefore, the type-specifier argument of a function declaration can specify any basic, structure, or union type. You can modify the function identifier with one or more asterisks (*) to declare a pointer return type. Functions declared as float always return a value of type float. In earlier versions of the Microsoft C compiler, the return value of a function using the obsolete form of a function declaration and returning type float was converted to type double. The Microsoft C version 7.0 compiler conforms to the ANSI standard by not changing the return type.
Although functions cannot return arrays and functions, they can return pointers to arrays and functions. You can declare a function that returns a pointer to an array or function type by modifying the function identifier with asterisks (*), brackets ([ ]), and parentheses ( ( ) ). Such a function identifier is known as a “complex declarator.” Rules for forming and interpreting complex declarators are discussed in “Interpreting More Complex Declarators”.
The following examples illustrate return types in function declarations:
void draw( void );
The draw function returns a void type (returns no value). The void keyword also replaces the list of parameters so no arguments are allowed for this function.
double ( *sum(double, double) )[3];
In this example, sum is declared as a function returning a pointer to an array of three double values. The sum function takes two double values as arguments.
int ( *select(void) )( int number );
The function named select takes no arguments and returns a pointer to a function. The pointer return value points to a function taking one int argument, represented by the identifier number, and returning an int value.
int prt( void * );
The function prt takes a pointer argument of any type and returns an int value. A pointer to any type could be passed as an argument to prt without producing a type-mismatch warning.
long ( *const rainbow[] ) ( int, ... ) ;
This array, named rainbow, contains an unspecified number of constant pointers to functions. Each of these takes at least one parameter of type int, as well as an unspecified number of other parameters. Each of the functions pointed to returns a long value.