30

When declaring functions in C, you should set a prototype in which you do not need to write the name of parameters. Just with its type is enough.

     void foo(int, char);

My question is, is it a good practice to also include names of parameters?

eversor
  • 3,031
  • 2
  • 26
  • 46
  • I thought C required parameter names (I don't know about C99, though). Maybe you're thinking of C++. – Marcelo Cantos Nov 17 '11 at 21:55
  • 4
    @MarceloCantos: no, C does not require them; even better, the C standard still even allows you to leave an empty parameters list, which means that no information about the parameters is given (C99, §6.7.5.3, ¶14); contrast this with C++, where it means that the function accepts no arguments. – Matteo Italia Nov 17 '11 at 22:11
  • 1
    @WTP: that was an ironical "better" :) Even the standard says (§6.11.6 ¶1) that "The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.", since it quite defeats part of the purpose of prototypes. – Matteo Italia Nov 17 '11 at 22:16
  • @MatteoItalia: I just realised that I'm confusing declarations and definitions. A *definition* requires parameter names in C — and not in C++ — but the declaration above is valid in either. – Marcelo Cantos Nov 17 '11 at 22:17

3 Answers3

35

Yes, it's considered good practice to name the arguments even in the prototypes.

You will usually have all your prototypes in the header file, and the header may be the only thing your users ever get to inspect. So having meaningful argument names is the first level of documentation for your API.

Likewise, comments about the what the functions do (not how they're implemented, of course) should go in the header, together with their prototypes.

A well-written header file may be the most important part of your library!


As a curious aside, constness of arguments is an implementation detail. So if you don't mutate an argument variable in your implementation, only put the const in the implementation:

/* Header file */

/* Computes a thingamajig with given base
 * in the given number of steps.
 * Returns half the thingamajig, or -1 on error.
 */
int super_compute(int base, int steps); 

/* implementation file */

#include "theheader.h"

int super_compute(const int base, int steps)
{
  int b = 2 * base;
  while (--steps) { b /= 8; } /* no need for a local variable :-) */
  return -1;
}

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 3
    Why would you want to deny knowledge of constness to the the client that only sees the header file? – David Heffernan Nov 17 '11 at 22:02
  • 3
    @DavidHeffernan: The arguments are passed by value, so there's nothing the user could possibly do with this information. – Kerrek SB Nov 17 '11 at 22:02
  • Also, this will make autocomplete more useful. –  Nov 17 '11 at 22:03
  • 1
    @WTP: Could you explain? I'm not familiar with autocomplete. – Kerrek SB Nov 17 '11 at 22:03
  • 4
    @Kerrek SB autocomplete means that when you type in part of a function or variable name, your editor can automatically expand it to the full symbol. This is similar to Google's autocomplete feature. The advantage of having argument names in prototypes here is that the editor can insert placeholders you can tab through, and those placeholders will be meaningful to the programmer. Just having "int" or "char *" doesn't describe what the argument is about. This is especially useful if a function has many arguments and you don't want to look up the documentation every time. –  Nov 17 '11 at 22:06
  • 2
    `int (int, int)` and `int (const int, int)` are incompatible types (C99 6.7.5.3 §15: *For two function types to be compatible [...] corresponding parameters shall have compatible types*, C99 6.7.3 §9: *For two qualified types to be compatible, both shall have the identically qualified version of a compatible type*), making this undefined behaviour; portable workaround: leave the declaration in the header files as-is and rename the parameter in the definition to `base_` and add `const int base = base_;` to the function body – Christoph Nov 17 '11 at 22:55
  • @Christoph: Interesting. Is this different from C++ then? I wouldn't try to work around this, I'd just leave out the `const` from the implementation if that's not allowed. – Kerrek SB Nov 17 '11 at 22:58
  • 1
    @Christoph: I'm not actually concerned about the function *types*, though. It's not like I'm juggling incompatible function pointers. This is literally just a matter of whether the linker will correctly resolve the symbol `foo` with the provided implementation. – Kerrek SB Nov 17 '11 at 23:01
  • @Kerrek SB: C specifies function calls in terms of function pointers (a function designator will be converted to a function pointer before the `()` postfix operator gets applied), so technically you are juggling with incompatible function pointers; in practice, parameter types are interchangeable as long as the types have identical representation and alignment, eg `void *` and `char *` (which is guaranteed by the standard) or even `int` and `long` on architectures where they have the same width (which is obviously not guaranteed by the standard) – Christoph Nov 17 '11 at 23:12
  • @Kerrek SB: I don't know C++ as well as C (and the C++ standard is somewhat harder to navigate due to sheer volume, so no standard quote for now), but I would find it surprising if C++ would be less strict than C in this particular case – Christoph Nov 17 '11 at 23:14
  • @Christoph: Well, the corners in which it *is* less strict are exactly these kinds of things. For example, C++ has a less restrictive notion of "constant expression" than C... OK, hopefully we can sort this out; I'd hate to give wrong advice! – Kerrek SB Nov 17 '11 at 23:15
  • @Kerrek SB: this seems indeed to be legal in C++: C++0x, february draft, 8.3.5 §5: *After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. [...] For example, `int(*)(const int p, decltype(p)*)` and `int(*)(int, const int*)` are identical types.* – Christoph Nov 17 '11 at 23:22
  • @Christoph: Ahh, great. Damn, I really like this idea, but I'll have to kill it if it's wrong in C. Are you sure then that this is UB in C? – Kerrek SB Nov 17 '11 at 23:24
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/5112/discussion-between-christoph-and-kerrek-sb) – Christoph Nov 17 '11 at 23:31
  • 3
    [I we ultimately concluded that this was indeed perfectly OK, both in C and in C++.] – Kerrek SB Nov 18 '11 at 01:20
10

I definitely recommend including the names of the parameters. If you're writing a library, it is certainly useful for those who will use your library to be able to glean what a function does from its prototype in your header files. Consider memcpy for instance. Without the names of the parameters, you'd be lost to know which is the source and which is the target. Finally, it is easier to include the names than to remove them when you copy your function definition to make it into a prototype. If you keep the names, you only need to add a semicolon at the end.

lhf
  • 70,581
  • 9
  • 108
  • 149
  • 1
    Isn't one of the `memcpy` arguments a pointer-to-const and the other a pointer-to-mutable? That sort of gives it away... – Kerrek SB Nov 17 '11 at 22:08
  • 1
    @Kerrek, you're right. I forgot about `const`. It shows how old I am... Perhaps `atan2` is a better example. – lhf Nov 17 '11 at 23:05
5

Some IDEs and editors will pull prototype information out of header files and provide the parameter information as hints while typing. If the names are available, that helps write code faster (and can help avoid some bugs).

Mark Wilkins
  • 40,729
  • 5
  • 57
  • 110