Creating functions
In old (pre-Standard) C, you could call a
function with any number or type of arguments and the compiler wouldn’t
complain. Everything seemed fine until you ran the program. You got mysterious
results (or worse, the program crashed) with no hints as to why. The lack of
help with argument passing and the enigmatic bugs that resulted is probably one
reason why C was dubbed a “high-level assembly
language.” Pre-Standard C programmers just adapted
to it.
Standard C and C++ use a feature called
function prototyping.
With function prototyping, you must use a description of the types of
arguments when declaring and defining a function. This description is the
“prototype.” When the function is called, the compiler uses the
prototype to ensure that the proper arguments are passed in and that the return
value is treated correctly. If the programmer makes a mistake when calling the
function, the compiler catches the mistake.
Essentially, you learned about function
prototyping (without naming it as such) in the previous chapter, since the form
of function declaration in C++ requires proper prototyping. In a function
prototype, the argument list contains the types of arguments that must be passed
to the function and (optionally for the declaration) identifiers for the
arguments. The order and type of the arguments must match in the declaration,
definition, and function call. Here’s an example of a function prototype
in a declaration:
int translate(float x, float y, float z);
You do not use the same form when
declaring variables in function prototypes as you do in ordinary variable
definitions. That is, you cannot say: float x, y, z. You must indicate
the type of each argument. In a function declaration, the following form
is also acceptable:
int translate(float, float, float);
Since the compiler doesn’t do
anything but check for types when the function is called, the identifiers are
only included for clarity when someone is reading the code.
In the function definition, names are
required because the arguments are referenced inside the
function:
int translate(float x, float y, float z) {
x = y = z;
// ...
}
It turns out this rule applies only to C.
In C++, an argument may be unnamed
in the argument list of the
function definition. Since it is unnamed, you cannot use it in the function
body, of course. Unnamed arguments are allowed to give the programmer a way to
“reserve space in the argument list.” Whoever uses the function must
still call the function with the proper arguments. However, the person creating
the function can then use the argument in the future without forcing
modification of code that calls the function. This option of ignoring an
argument in the list is also possible if you leave the name in, but you will get
an annoying warning message about the value being unused every time you compile
the function. The warning is eliminated if you remove the name.
C and C++ have two other ways to declare
an argument list. If you have an
empty
argument list, you can declare it as func( ) in C++, which tells the
compiler there are exactly zero arguments. You should be aware that this only
means an empty argument list in C++. In C it means “an indeterminate
number of arguments (which is a “hole” in C since it disables type
checking in that case). In both C and C++, the declaration func(void);
means an empty argument list. The
void keyword means
“nothing” in this case (it can also mean “no type” in
the case of pointers, as you’ll see later in this
chapter).
The other option for argument lists
occurs when you don’t know how many arguments or what type of arguments
you will have; this is called a variable argument
list.
This “uncertain argument list” is represented by ellipses
(...). Defining a function with a variable
argument list is significantly more complicated than defining a regular
function. You can use a variable argument list for a function that has a fixed
set of arguments if (for some reason) you want to disable the error checks of
function prototyping. Because of this, you should restrict your use of variable
argument lists to C and avoid them in C++ (in which, as you’ll learn,
there are much better alternatives). Handling variable argument lists is
described in the library section of your local C
guide.