Correct function prototype format for ANSI C

R

Roy Hills

I've seen two different function prototype formats used for ANSI C,
and I'm unsure as to which is the correct or preferred one.

1st Format (this is what I use)

type function(type, type, type);

e.g. "int multiply(int, int);"

2nd Format (I've seen this used in other people's code)

type function(type param, type param);

e.g. "int multiply(int first, int second);"

So the first format just gives the types, whereas the second format
gives the parameters as well. The second format is just re-stating
the function declaration.

I currently use the first format, and it works on many different C
compilers. I've also seen the second format used in other code, and
that works fine, with GCC at least.

I typically use GCC, but it's important that my code work on other
compilers as well as I maintain code which needs to be portable. My
code is ANSI C; I'm not concerned with C++.

I can't see this mentioned in the FAQ, although it would seem to be an
obvious question (to me at least). Apologies if the answer is equally
obvious.

Roy
 
R

Richard Bos

Roy Hills said:
I've seen two different function prototype formats used for ANSI C,
and I'm unsure as to which is the correct or preferred one.

1st Format (this is what I use)

type function(type, type, type);

e.g. "int multiply(int, int);"

2nd Format (I've seen this used in other people's code)

type function(type param, type param);

e.g. "int multiply(int first, int second);"

Both are correct. Which is preferred depends on style; a common argument
against the second type is that the parameter names can cause clashes
with already defined variables, but this is easily circumvented using a
little care, and many people like the extra information.
Note that in the second type, the names in the prototype need not agree
with the names in the definition; only the types must.

Richard
 
B

bjrnove

Both format's actually are the same. The nice thing about the 2nd
format is that you are able to tell the reader of a headerfile what the
different variables are.

int myfunc(int, int); /* This is the part the compiler look at */

int myfunc(int apples, int oranges); /* This is much more
understandable, but the compiler sees it as the one above */
 
?

=?iso-8859-1?q?Dag-Erling_Sm=F8rgrav?=

Roy Hills said:
I've seen two different function prototype formats used for ANSI C,
and I'm unsure as to which is the correct or preferred one.

1st Format (this is what I use)

type function(type, type, type);

e.g. "int multiply(int, int);"

This is correct and sufficient.
2nd Format (I've seen this used in other people's code)

type function(type param, type param);

e.g. "int multiply(int first, int second);"

This is also correct, and some prefer it because it provides a clue to
the meaning of the arguments.

The problem with the second form is namespace pollution. You can
usually make sure that the argument names don't conflict at the point
where your code is compiled, but you can't be sure they won't conflict
when third parties writing code that links against your library
include your header.

Some people (including me) prepend argument names in the prototype
with underscores to preserve the documentation value while avoiding
namespace collisions. From a standards point of view, this is
actually worse, because names that begin with underscores are in the
implementation namespace. Still, they are less likely to collide, and
you are more likely to detect a collision during development.

If you provide good documentation for your library, there should be no
need for users to read the headers, and hence no need for prototypes
to include argument names.

DES
 
C

Christian Kandeler

Richard said:
Both are correct. Which is preferred depends on style; a common argument
against the second type is that the parameter names can cause clashes
with already defined variables

Huh? There are variables sharing namespace with formal parameters of
function prototypes? I have never heard that before. Could you give an
example?


Christian
 
K

Kevin Bracey

The problem with the second form is namespace pollution. You can
usually make sure that the argument names don't conflict at the point
where your code is compiled, but you can't be sure they won't conflict
when third parties writing code that links against your library
include your header.

One shouldn't overstate the scale of this problem. It only strikes if you
have the identifier's name already #defined as something odd, or it is a
typedef name. Or an enum, I suppose. But it doesn't matter if you've got a
variable or function called "first" in scope.

The chances of a clash are very slim, as long as you aren't in the habit of
defining a lot of lower case macros. I've never seen it happen in practice.

The Standard Library implementation does need to avoid the possibility
though. The way our library deals with this while keeping the prototypes
clear is very simple:

int div(int /*numer*/, int /*denom*/);
 
K

Kevin Bracey

In message <[email protected]>
Christian Kandeler said:
Huh? There are variables sharing namespace with formal parameters of
function prototypes? I have never heard that before. Could you give an
example?

The parameters of a prototype _are_ part of the same namespace as all
variables, but the prototype is a new inner scope, so the identifiers
just mask any existing ones. This is the same rule as for normal nested
scopes.

Thus:

extern int i;
{
int i; /* ok - masks global i */
{
int i; /* ok - masks outer i */
int i; /* error - redefinition */
}
}

and the same:

extern int i;
extern void j(void);

void foo(int i, /* ok - masks global i */
int j, /* ok - masks global j */
int i /* error - redefinition */
);

So there's no need to worry about parameter names clashing with already
defined objects or functions.
 
C

Chris Torek

The parameters of a prototype _are_ part of the same namespace as all
variables, but the prototype is a new inner scope ... [examples snipped]
So there's no need to worry about parameter names clashing with already
defined objects or functions.

Right. Where the problem comes in, however, is when you are not
in control of all the code. For instance, suppose I am the
implementor writing the <string.h> file that you, the user, will
include later. Suppose further that I do this:

/* string.h - ANSI C string functions */
[snippage]
char *strcpy(char *destination, const char *source);
[more snippage]

Now suppose *you*, the user of my implementation, do this:

#define destination Kyoto: the anagram lover's Tokyo!

#include <string.h>

While I would argue that this is not good C code, this *is* *valid*
C code (that you just wrote). The C standard says it has to work.
Unfortunately, it fails, because *I*, the implementor, used the
name "destination" in my prototype for strcpy. When the (actual
text, in this case) file <string.h> is included -- after your
#define -- the strcpy declaration line expands to:

char *strcpy(char *Kyoto: the anagram lover's Tokyo!, const char *source);

and you get a syntax error -- because I used the name "destination"
in my prototype.

The easiest way for me, the implementor, to avoid this problem is for
me to omit the parameter names. Another option is for me to use the
names reserved to me, such as those starting with double underscores:

char *strcpy(char *__destination, const char *__source);

Of course, you -- the user -- had better *not* use names starting
with double-underscore.

If you are a "lone" end-user, in control of your entire portion of
the namespace, you need not worry about this. But what if you are
part of a team, or are a third-party library supplier? What names
will you use? (The C standards have no answer for you; you must
make up your own rules.)
 
C

Christian Kandeler

Chris said:
Kevin Bracey said:
The parameters of a prototype _are_ part of the same namespace as all
variables, but the prototype is a new inner scope ... [examples snipped]
So there's no need to worry about parameter names clashing with already
defined objects or functions.

Right. Where the problem comes in, however, is when you are not
in control of all the code. For instance, suppose I am the
implementor writing the <string.h> file that you, the user, will
include later. Suppose further that I do this:

/* string.h - ANSI C string functions */
[snippage]
char *strcpy(char *destination, const char *source);
[more snippage]

Now suppose *you*, the user of my implementation, do this:

#define destination Kyoto: the anagram lover's Tokyo!

Okay, with suitable macro definitions I can easily invalidate even the most
correct code, but how would you do that with variable names? John Bos
stated that "parameter names [in function prototypes] can cause clashes
with already defined variables". I still don't see how, as the parameter
have almost no scope to speak of and are not used for anything.


Christian
 
K

Kevin Bracey

In message <[email protected]>
Chris Torek said:
The parameters of a prototype _are_ part of the same namespace as all
variables, but the prototype is a new inner scope ... [examples snipped]
So there's no need to worry about parameter names clashing with already
defined objects or functions.

Right. Where the problem comes in, however, is when you are not
in control of all the code.

[snip]

char *strcpy(char *__destination, const char *__source);

I addressed all that in my other post, but thanks for going into more tedious
detail than I was prepared to. As I said, I prefer:

char *strcpy(char * /*destination*/, const char * /*source*/);

Somewhat neater, and it looks prettier in my syntax colouring.
 
C

CBFalconer

Roy said:
I've seen two different function prototype formats used for ANSI C,
and I'm unsure as to which is the correct or preferred one.

1st Format (this is what I use)

type function(type, type, type);

e.g. "int multiply(int, int);"

2nd Format (I've seen this used in other people's code)

type function(type param, type param);

e.g. "int multiply(int first, int second);"

So the first format just gives the types, whereas the second format
gives the parameters as well. The second format is just re-stating
the function declaration.

I currently use the first format, and it works on many different C
compilers. I've also seen the second format used in other code,
and that works fine, with GCC at least.

I typically use GCC, but it's important that my code work on other
compilers as well as I maintain code which needs to be portable.
My code is ANSI C; I'm not concerned with C++.

I can't see this mentioned in the FAQ, although it would seem to
be an obvious question (to me at least). Apologies if the answer
is equally obvious.

My advice is to always use what you call the second format, and to
avoid generating separate prototypes at all as far as possible.
You do this by defining functions before use, and by marking static
all functions that are not to be exported from a particular
compilation unit. Then you only need separate prototypes in header
files (for export) or because of mutual recursion. The prototypes
are more understandable when the parameters have names. Consider:

int divide(int, int);
and
int divide(int dividend, int divisor);

and think about which is more likely to be used correctly.
 
A

Andrey Tarasevich

Roy said:
I've seen two different function prototype formats used for ANSI C,
and I'm unsure as to which is the correct or preferred one.

1st Format (this is what I use)

type function(type, type, type);

e.g. "int multiply(int, int);"

2nd Format (I've seen this used in other people's code)

type function(type param, type param);

e.g. "int multiply(int first, int second);"

So the first format just gives the types, whereas the second format
gives the parameters as well. The second format is just re-stating
the function declaration.
...

Both formats are correct. And both have their benefits and drawbacks.
The second format creates more self-documenting declaration, since it
gives you the opportunity to assign informative names to the parameters.
However, it requires more maintenance, since you have to remember to
keep the parameter names synchronized between the declaration and the
definition (it is not required by the language, but it might become
confusing if they get out of sync).
 
E

Emmanuel Delahaye

Roy Hills wrote on 11/03/05 :
I've seen two different function prototype formats used for ANSI C,
and I'm unsure as to which is the correct or preferred one.

1st Format (this is what I use)

type function(type, type, type);

e.g. "int multiply(int, int);"

2nd Format (I've seen this used in other people's code)

type function(type param, type param);

e.g. "int multiply(int first, int second);"
Both are conforming to the standard. The second form has my preference,
because it is 'self-documenting', and I think that is is a Good Thing
(c). BTW, building it only needs a copy from the header of the
definition of the function and to add a trailing semicolon. It's neat
and simple.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++
 
R

Richard Bos

Christian Kandeler said:
Richard Bos wrote:

Huh? There are variables sharing namespace with formal parameters of
function prototypes? I have never heard that before. Could you give an
example?

Sorry; I should have said already #defined constants, of course. For
example

#define size 4

struct list *makelist(int size, int value);

Richard
 

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

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,276
Latest member
Sawatmakal

Latest Threads

Top