6.5. Function Prototypes and Argument
Coercion
A function prototype (also called a
function declaration) tells the compiler the name of a function, the type of
data returned by the function, the number of parameters the function expects to
receive, the types of those parameters and the order in which the parameters of
those types are expected.
Software Engineering Observation 6.4
|
Function
prototypes are required in C++. Use #include
preprocessor directives to obtain function prototypes for the C++ Standard
Library functions from the header files for the appropriate libraries (e.g., the
prototype for math function sqrt is in header file
<cmath>; a partial list of C++ Standard Library header files
appears in Section
6.6). Also use #include to obtain header
files containing function prototypes written by you or your group
members. |
Common Programming Error 6.3
|
If a
function is defined before it is invoked, then the function's definition also
serves as the function's prototype, so a separate prototype is unnecessary. If a
function is invoked before it is defined, and that function does not have a
function prototype, a compilation error
occurs. |
Software Engineering Observation 6.5
|
Always provide
function prototypes, even though it is possible to omit them when functions are
defined before they are used (in which case the function header acts as the
function prototype as well). Providing the prototypes avoids tying the code to
the order in which functions are defined (which can easily change as a program
evolves). |
Function Signatures
The portion of a function prototype that
includes the name of the function and the types of its arguments is called the
function
signature or simply the signature. The function signature does not specify the function's
return type. Functions in the same scope must have unique signatures. The scope
of a function is the region of a program in which the function is known and
accessible. We'll say more about scope in Section
6.10.
Common Programming Error 6.4
|
It is a
compilation error if two functions in the same scope have the same signature but
different return types. |
In Fig.
6.2, if the function prototype in line 17
had been written
void maximum( int, int, int );
the compiler would report an error,
because the void return type in the function prototype would differ
from the int return type in the function
header. Similarly, such a prototype would cause the statement
cout << maximum( 6, 7, 0 );
to generate a compilation error,
because that statement depends on maximum to return
a value to be displayed.
Argument Coercion
An important feature of function prototypes is argument coercion—i.e.,
forcing arguments to the appropriate types specified by the parameter
declarations. For example, a program can call a function with an integer
argument, even though the function prototype specifies a double argument—the function will still work correctly.
Argument Promotion Rules
Sometimes, argument values that do not
correspond precisely to the parameter types in the function prototype can be
converted by the compiler to the proper type before the function is called.
These conversions occur as specified by C++'s promotion rules. The
promotion rules indicate how to convert between types without losing data. An
int can be converted to a double without changing its value. However, a double converted to
an int truncates the fractional part of the double value. Keep
in mind that double variables can hold numbers of much greater
magnitude than int variables, so the loss of data may be considerable. Values may also be
modified when converting large integer types to small integer types (e.g.,
long to short), signed to unsigned or unsigned to signed.
The promotion rules apply to
expressions containing values of two or more data types; such expressions are
also referred to as mixed-type
expressions. The type of each value in a
mixed-type expression is promoted to the "highest" type in the expression
(actually a temporary version of each value is created and used for the
expression—the original values remain unchanged). Promotion also occurs when the
type of a function argument does not match the parameter type specified in the
function definition or prototype. Figure 6.5 lists the fundamental data
types in order from "highest type" to "lowest type."
Fig. 6.5. Promotion hierarchy for fundamental data
types.
| Data types |
| long double |
|
| double |
|
| float |
|
| unsigned long int |
(synonymous with unsigned long) |
| long int |
(synonymous with long) |
| unsigned int |
(synonymous with unsigned) |
| int |
|
| unsigned short int |
(synonymous with unsigned short) |
| short int |
(synonymous with short) |
| unsigned char |
|
| char |
|
| bool |
|
Converting values to lower fundamental
types can result in incorrect values. Therefore, a value can be converted to a
lower fundamental type only by explicitly assigning the value to a variable of
lower type (some compilers will issue a warning in this case) or by using a cast
operator (see Section
4.7). Function argument values are converted
to the parameter types in a function prototype as if they were being assigned
directly to variables of those types. If a square function that uses an integer parameter is called with a
floating-point argument, the argument is converted to int (a lower
type), and square could return an
incorrect value. For example, square( 4.5 ) returns 16, not
20.25.
Common Programming Error 6.5
|
Converting
from a higher data type in the promotion hierarchy to a lower type, or between
signed and unsigned, can corrupt the data value, causing a loss of
information. |
Common Programming Error 6.6
|
It is a
compilation error if the arguments in a function call do not match the number
and types of the parameters declared in the corresponding function prototype. It
is also an error if the number of arguments in the call matches, but the
arguments cannot be implicitly converted to the expected
types. |