Prototypes
Our first look at a prototype is in the next program [PROTYPE1.CPP].
The prototyping used in C++ is no different to that used in ANSI-C.
Actually, many C programmers take a rather dim view of prototyping
and seem reluctant to use it, but with C++ it is considerably more
important and is in much heavier use. In fact, prototyping is required to
be used in most modern C++ compilers.
#include <iostream.h>
void do_stuff(int wings, float feet, char eyes);
void main()
{
int arm = 2;
float foot = 1000.0;
char lookers = 2;
do_stuff(3, 12.0, 4);
do_stuff(arm, foot, lookers);
}
void do_stuff(int wings, float feet, char eyes)
{
cout << "There are " << wings << " wings." << "\n";
cout << "There are " << feet << " feet." << "\n";
cout << "There are " << (int)eyes << " eyes." << "\n\n";
}
A prototype is a limited model of a more complete entity to come later.
In this case, the full function is the complete entity to come later and the
prototype is illustrated in line 2. The prototype gives a model of the
interface to the function that can be used to check the calls to the
function for the proper number of parameters and the correct types of
parameters. Each call to the function named do_stuff() must have
exactly three parameters or the compiler will give an error message. In
addition to the correct number of parameters, the types must be
compatible or the compiler will issue an error message. Notice that
when the compiler is working on lines 8 and 9, the type checking can be
done based on the prototype in line 2 even though the function itself is
not yet defined. If the prototype is not given, the number of parameters
will not be checked, nor will the types of the parameters be checked.
Even if you have the wrong number of parameters, you will get an
apparently good compile and link, but the program may do some very
strange things when it is executed.
To write the prototype, simply copy the header from the function to the
beginning of the program and append a semicolon to the end as a signal
to the compiler that this is not a function but a prototype. The variable
names given in the prototype are optional and act merely as comments
to the program reader since they are completely ignored by the
compiler. You could replace the variable name wings in line 2 with your
first name and there would be no difference in compilation. Of course,
the next person that had to read your program would be somewhat
baffled with your choice of variable names. In this case, the two
function calls to this function, given in lines 8 and 9, are correct so no
error will be listed during compilation.
Even though we wish to use the char type for eyes in the function, we
wish to use it as a number rather than as a character. The cast to int in
line 15 is required to force the printout of the numerical value rather
than an ASCII character. The next example program is similar but
without the cast to int.
Compatible types
Compatible types complete our discussion of prototyping. Compatible
types are any simple types that can be converted from one to another in
a meaningful way. For example, if you used an integer as the actual
parameter and the function was expecting a float type as the formal
parameter, the system would do the conversion automatically, without
mentioning it to you. This is also true of a float changing to a char, or a
char changing to an int. There are definite conversion rules which
would be followed. These rules are given in great detail in the ANSI-C
standard and are also given in the second edition of the Kernighan and
Ritchie.
If we supplied a pointer to an integer as the actual parameter and
expected an integer as the formal parameter in the function, the
conversion would not be made because they are two entirely different
kinds of values. Likewise, a structure would not be converted
automatically to a long float, an array, or even to a different kind of
structure, they are all incompatible and cannot be converted in any
meaningful manner. The entire issue of type compatibility as discussed
earlier in the tutorial applies equally well to the compatibility of types
when calling a function. Likewise, the type specified as the return type,
in this case void, must be compatible with the expected return type in
the calling statement, or the compiler will issue a warning.
This is your chance to try prototyping for yourself and see how well it
works and what kinds of error messages you get when you do certain
wrong things. Change the actual parameters in line 8 of the program
above to read (12.2, 13, 12345) and see what the compiler says about
that change. It will probably say nothing because they are all type
compatible. If you change it to read (12.0, 13), it will issue a warning or
error because there are not enough arguments given.
Likewise you should receive an error message if you change one of the
parameters in line 9 to an address by putting an ampersand in front of
one of the variable names. Finally, change the first word in line 3 from
void to int and see what kind of error message is given. You will first be
required to make the function header in line 9 agree with the prototype,
then you will find that there is no variable returned from the function.
You should the (correct) impression that prototyping is doing
something useful after making these changes.
More prototyping
The next example program [PROTYPE2.CPP] includes a little more
information on prototyping.
#include <iostream.h>
void do_stuff(int, float, char);
void main()
{
int arm = 2;
float foot = 1000.0;
char lookers = 65;
do_stuff(3, 12.0, 67);
do_stuff(arm, foot, lookers);
}
void do_stuff(int wings, // Number of wings
float feet, // Number of feet
char eyes) // Number of eyes
{
cout << "There are " << wings << " wings." << "\n";
cout << "There are " << feet << " feet." << "\n";
cout << "There are " << eyes << " eyes." << "\n\n";
}
This program is identical to the last one except for a few small changes.
The variable names have been omitted from the prototype in line 2
merely as an illustration that they are interpreted as comments by the
C++ compiler. The function header is formatted differently to allow for
a comment alongside each of the actual parameters. This should make
the function header a little more self explanatory. However, you should
remember that comments should not be used to replace careful selection
of variable names. In this particular case, the comments add essentially
nothing to the clarity of the program.
Links: Home C Programming Guide C++ programming Guide