United States |
Previous | Contents | Index |
A function can be called without declaring it if the function's return value is int (although this practice is not recommended due to the loss of type-checking capability; all functions should be declared). If the return value is anything else, and if the function definition is located after the calling function in the source code, the function must be declared before calling it. For example:
char lower(int c); /* Function declaration */ caller() /* Calling function */ { int c; char c_out; . . . c_out = lower(c); /* Function call */ } char lower(int c_up) /* Function definition */ { . . . } |
If the function definition for lower was located before the function caller in the source code, lower would not have to be declared again before calling it. In that case, the function definition would serve as its own declaration and would be in scope for any function calls from within all subsequently defined functions in the same source file.
Note that both the function definition and function declaration for lower are in the prototype style. Although C supports the old style of function declaration in which the parameter types are not specified in the function declarator, it is good programming practice to use prototype declarations for all user-defined functions in your program, and to place the prototypes before the first use of the function. Also note that it is valid for the parameter identifier in the function declaration to be different from the parameter identifier in the function definition.
In a function declaration, the void keyword should be used to specify an empty argument list. For example:
char function_name(void); |
As with function definitions, the void keyword can also be used in function declarations to specify the return value type for functions that do not return a value. For example:
main() { void function_name( ); . . . } void function_name( ) { } |
A function prototype is a function declaration that specifies the data types of its arguments in the parameter list. The compiler uses the information in a function prototype to ensure that the corresponding function definition and all corresponding function declarations and calls within the scope of the prototype contain the correct number of arguments or parameters, and that each argument or parameter is of the correct data type.
Prototypes are syntactically distinguished from the old style of function declaration. The two styles can be mixed for any single function, but this is not recommended. The following is a comparison of the old and the prototype styles of declaration:
The Compaq C compiler will warn about old-style function declarations only in strict ANSI standard mode, or when the check compiler option is specified. |
Prototype style:
A function prototype has the following syntax:
function-prototype-declaration:
declaration-specifiersopt declarator; |
The declarator includes a parameter type list, which specifies the types of, and can declare identifiers for, the parameters of the function.
A parameter type list can consist of a single parameter of type void to specify that the function has no parameters.
A parameter type list can contain a member that is a variable-length array, specified by the [*] notation.
In its simplest form, a function prototype declaration might have the following format:
storage_classopt return_typeopt function_name ( type1 parameter1, ..., typen parametern ); |
Consider the following function definition:
char function_name( int lower, int *upper, char (*func)(), double y ) { } |
The corresponding prototype declaration for this function is:
char function_name( int lower, int *upper, char (*func)(), double y ); |
A prototype is identical to the header of its corresponding function definition specified in the prototype style, with the addition of a terminating semicolon (;) or comma (,), as appropriate (depending on whether the prototype is declared alone or in a multiple declaration).
Function prototypes need not use the same parameter identifiers as in the corresponding function definition because identifiers in a prototype have scope only within the identifier list. Moreover, the identifiers themselves need not be specified in the prototype declaration; only the types are required.
For example, the following prototype declarations are equivalent:
char function_name( int lower, int *upper, char (*func)(), double y ); char function_name( int a, int *b, char (*c)(), double d ); char function_name( int, int *, char (*)(), double ); |
Though not required, identifiers should be included in prototypes to improve program clarity and increase the type-checking capability of the compiler.
Variable-length argument lists are specified in function prototypes with ellipses. At least one parameter must precede the ellipses. For example:
char function_name( int lower, ... ); |
Data-type specifications cannot be omitted from a function prototype.
5.5.2 Scope and Conversions
Prototypes must be placed appropriately in each compilation unit of a program. The position of the prototype determines its scope. A function prototype, like any function declaration, is considered within the scope of a corresponding function call only if the prototype is specified within the same block as the function call, any enclosing block, or at the outermost level of the source file. The compiler checks all function definitions, declarations, and calls from the position of the prototype to the end of its scope. If you misplace the prototype so that a function definition, declaration, or call occurs outside the scope of the prototype, any calls to that function behave as if there were no prototype.
The syntax of the function prototype is designed so that you can extract the function header of each of your function definitions, add a semicolon (;), place the prototypes in a header, and include that header at the top of each compilation unit in your program. In this way, function prototypes are declared to be external, extending the scope of the prototype throughout the entire compilation unit. To use prototype checking for C library function calls, place the #include preprocessor directives for the .h files appropriate for the library functions used in the program.
It is an error if the number of arguments in a function definition, declaration, or call does not match the prototype.
If the data type of an argument in a function call does not match the corresponding type in the function prototype, the compiler tries to perform conversions. If the mismatched argument is assignment-compatible with the prototype parameter, the compiler converts the argument to the data type specified in the prototype, according to the argument conversion rules (see Section 5.6.1).
If the mismatched argument is not assignment-compatible with the
prototype parameter, an error message is issued.
5.6 Parameters and Arguments
C functions exchange information by means of parameters and arguments. The term parameter refers to any declaration within the parentheses following the function name in a function declaration or definition; the term argument refers to any expression within the parentheses of a function call.
The following rules apply to parameters and arguments of C functions:
In a function call, the types of the evaluated arguments must match the types of their corresponding parameters. If they do not match, the following conversions are performed in a manner that depends on whether a prototype is in scope for the function:
void f(char, short, float, ...); char c1, c2; short s1,s2; float f1,f2; f(c1, s1, f1, c2, s2, f2); |
No other default conversions are performed on arguments. If a
particular argument must be converted to match the type of the
corresponding parameter, use the cast operator. For more information
about the cast operator, see Section 6.4.6.
5.6.2 Function and Array Identifiers as Arguments
Function and array identifiers can be specified as arguments to a function. Function identifiers are specified without parentheses, and array identifiers are specified without brackets. When so specified, the function or array identifier is evaluated as the address of that function or array. Also, the function must be declared or defined, even if its return value is an integer. Example 5-1 shows how and when to declare functions passed as arguments, and how to pass them.
Example 5-1 Declaring Functions Passed as Arguments |
---|
(1)int x() { return 25; } /* Function definition and */ int z[10]; /* array defined before use */ (2)fn(int f1(), int (*f2)(), int a1[])) /* Function definition */ { f1(); /* Call to function f1 */ . . . } void caller(void) { (3) int y(); /* Function declaration */ . . . (4) fn(x, y, z); /* Function call: functions */ /* x and y, and array z */ /* passed as addresses */ . . . } int y(void) { return 30; } /* Function definition */ |
Key to Example 5-1:
fn(int f1(), int f2(), int a1[]) /* f1, f2 declared as */ {...} /* functions; a1 declared */ /* as array of int. */ fn(int (*f1)(), int (*f2)(), int *a1) /* f1, f2 declared as */ {...} /* pointers to functions; */ /* a1 declared as pointer */ /* to int. */ |
The function called at program startup is named main . The main function can be defined with no parameters or with two parameters (for passing command-line arguments to a program when it begins executing). The two parameters are referred to here as argc and argv, though any names can be used because they are local to the function in which they are declared. A main function has the following syntax:
int main(void) {...} |
int main(int argc, char *argv[ ]) {...}) |
argc
The number of arguments in the command line that invoked the program. The value of argc is nonnegative.argv
Pointer to an array of character strings that contain the arguments, one per string. The value argv[argc] is a null pointer.
If the value of argc is greater than zero, the array members argv[0] through argv[argc -- 1] inclusive contain pointers to strings, which are given implementation-defined values by the host environment before program startup. The intent is to supply the program with information determined before program startup from elsewhere in the host environment. If the host environment cannot supply strings with letters in both uppercase and lowercase, the host environment ensures that the strings are received in lowercase.
If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] is the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc -- 1] represent the program parameters.
The parameters argc and argv, and the strings pointed to by the argv array, can be modified by the program and keep their last-stored values between program startup and program termination.
In the main function definition, parameters are optional. However, only the parameters that are defined can be accessed.
See your platform-specific Compaq C documentation for more information on the passing and return of arguments to the main function.
Previous | Next | Contents | Index |
|