Which function header do you prefer?

I

istillshine

int foo(x, y, z)
double *x;
int y;
double z;
{
/* do something */
}

or

int foo(double *x, int y, double z)
{
/* do something */
}


I notice the first one appeared in 1978's The C Programming Language
book.
The second edition of the book adopted the second one. The first one
seem more
readable when there are many arguments.
 
H

Hallvard B Furuseth

int foo(x, y, z)
double *x;
int y;
double z;
{
/* do something */
}

or

int foo(double *x, int y, double z)
{
/* do something */
}


I notice the first one appeared in 1978's The C Programming Language
book.

The 2nd form is called a prototype, and makes the compiler do type
checking on the arguments and convert them to the types of the parameter
if needed. E.g.
int foo(x) long x; {...}
... foo(3); ...
is wrong, it should have been foo(3L). But foo(3) is correct if
you used a prototype: int foo(long x);'.
The second edition of the book adopted the second one. The first one
seem more readable when there are many arguments.

Then write the 2nd like this:
int foo(
double *x,
int y,
double z)
 
M

Martin Ambuhl

int foo(x, y, z)
double *x;
int y;
double z;
{
/* do something */
}

or

int foo(double *x, int y, double z)
{
/* do something */
}


I notice the first one appeared in 1978's The C Programming Language
book.
The second edition of the book adopted the second one. The first one
seem more
readable when there are many arguments.

There are more issues than readability.
The first form, by not specifying the types in the parameter list,
applies standard rules of promotion of types but does not lead to
checking that the types match. The second allows the compiler to check
that the values of the types of the arguments in an invocation of the
function are convertible to the the types of the parameters the function
expects, and if they
a) are not convertible to issue a diagnostic, and
b) are convertible but not identical to apply the appropriate conversion.

Suppose you had the simple function
double square(x)
double x;
{
return x*x;
}
and called it with
square(1);
The compiler will generate a call with an _int_ of value 1, which
may not bear any semblance to a _double_ with value 1.

But suppose you had the simple function
double square(double x)
{
return x*x;
}
and called it with
square(1);
The compiler can now convert value 1 to a double and pass that to the
function.

You might ask why you can't do that with the first kind of function
definition. You could, it you were building a language from the ground
up, but the rules for the first way of handling argument lists were
established before the second way existed.

As for readability, suppose you use whitespace to rewrite the second as
int foo(double *x,
int y,
double z)
{ /* .... */ }

The whitespace does nothing to the meaning, but it now has all the
advantages you might see in
int foo(x, y, z)
double *x;
int y;
double z;
{ /* .... */ }
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top