228

What is better: void foo() or void foo(void)? With void it looks ugly and inconsistent, but I've been told that it is good. Is this true?

Edit: I know some old compilers do weird things, but if I'm using just GCC, is void foo() Ok? Will foo(bar); then be accepted?

Zifre
  • 24,944
  • 8
  • 81
  • 102

6 Answers6

277
void foo(void);

That is the correct way to say "no parameters" in C, and it also works in C++.

But:

void foo();

Means different things in C and C++! In C it means "could take any number of parameters of unknown types", and in C++ it means the same as foo(void).

Variable argument list functions are inherently un-typesafe and should be avoided where possible.

Daniel Earwicker
  • 108,589
  • 35
  • 194
  • 274
  • 70
    Note that void foo(); does not mean a varargs function; it just means that the compiler hasn't been told what its args are. A varargs function must (according to the standard) be declared with the ellipsis. Also, void foo() { ... } - function definition instead of declaration - is OK (though consistency suggests using void foo(void) { ... } here too). – Jonathan Leffler Jun 20 '09 at 14:05
  • 4
    You say "the compiler hasn't been told what its args are", I say "it could take any number of parameters of unknown types". What's the difference? – Daniel Earwicker Jun 20 '09 at 15:41
  • 11
    He says that the compiler hasn't been told about the number / type of the arguments. But you say the function could take any number of parameters of unknown types. But that's what `...` is for (varargs function). This sounds a bit confusing, but i think you wanted to say "cold take a certain number of arguments, but this number isn't known". It's like this: You have a pot, and dunno how many liters it can take. But that doesn't mean the pot can take any number of liters. At a certain amount, it just overflows :) So for `void foo()`: For some amounts/types, it just causes undefined behavior – Johannes Schaub - litb Jul 22 '09 at 10:35
  • 3
    `()` is declared an obsolescent feature in C99. I think the only confusion here has arisen because I mentioned that vararg lists are unsafe immediately after discussing empty parameter lists. This was simply because I imagine someone reading the explanation and then thinking "Oh, I wonder what amazing things I can achieve with this feature?" Then the next thing they'll find out about is using `...` to write functions like `printf`, and I wanted to discourage that right away. Far from suggesting that `()` is the way to do varargs, I'm saying that it best to avoid varargs altogether. – Daniel Earwicker Jul 22 '09 at 11:52
  • 2
    It seems to me that void foo(void); could easily be confused with void foo(void*); , whereas foo() wouldn't likely be confused with foo(void*); – ArtOfWarfare Oct 08 '12 at 20:16
  • @DanielEarwicker: Non-prototype function declarations have been obsolescent since ANSI C89. (Which means they could be removed in a future standard, but even C11 has left them in place -- unfortunately, IMHO.) – Keith Thompson Sep 16 '13 at 03:00
  • In C, `void foo(void);` is correct. In C++, `void foo();` is better; C++ permits `void foo();` only for compatibility with C. Remember, C and C++ are two different languages. – Keith Thompson Sep 16 '13 at 03:01
  • @KeithThompson do you mean to say that 'C++ supports `void foo(void);` only for compatibility with C'? – RastaJedi Apr 25 '16 at 07:25
  • @RastaJedi: Yes, that's what I meant. – Keith Thompson Apr 25 '16 at 07:27
94

There are two ways for specifying parameters in C. One is using an identifier list, and the other is using a parameter type list. The identifier list can be omitted, but the type list can not. So, to say that one function takes no arguments in a function definition you do this with an (omitted) identifier list

void f() {
    /* do something ... */
}

And this with a parameter type list:

void f(void) {
    /* do something ... */
}

If in a parameter type list the only one parameter type is void (it must have no name then), then that means the function takes no arguments. But those two ways of defining a function have a difference regarding what they declare.

Identifier lists

The first defines that the function takes a specific number of arguments, but neither the count is communicated nor the types of what is needed - as with all function declarations that use identifier lists. So the caller has to know the types and the count precisely before-hand. So if the caller calls the function giving it some argument, the behavior is undefined. The stack could become corrupted for example, because the called function expects a different layout when it gains control.

Using identifier lists in function parameters is deprecated. It was used in old days and is still present in lots of production code. They can cause severe danger because of those argument promotions (if the promoted argument type do not match the parameter type of the function definition, behavior is undefined either!) and are much less safe, of course. So always use the void thingy for functions without parameters, in both only-declarations and definitions of functions.

Parameter type list

The second one defines that the function takes zero arguments and also communicates that - like with all cases where the function is declared using a parameter type list, which is called a prototype. If the caller calls the function and gives it some argument, that is an error and the compiler spits out an appropriate error.

The second way of declaring a function has plenty of benefits. One of course is that amount and types of parameters are checked. Another difference is that because the compiler knows the parameter types, it can apply implicit conversions of the arguments to the type of the parameters. If no parameter type list is present, that can't be done, and arguments are converted to promoted types (that is called the default argument promotion). char will become int, for example, while float will become double.

Composite type for functions

By the way, if a file contains both an omitted identifier list and a parameter type list, the parameter type list "wins". The type of the function at the end contains a prototype:

void f();
void f(int a) {
    printf("%d", a);
}

// f has now a prototype. 

That is because both declarations do not say anything contradictory. The second, however, had something to say in addition. Which is that one argument is accepted. The same can be done in reverse

void f(a) 
  int a;
{ 
    printf("%d", a);
}

void f(int);

The first defines a function using an identifier list, while the second then provides a prototype for it, using a declaration containing a parameter type list.

Johannes Schaub - litb
  • 466,055
  • 116
  • 851
  • 1,175
  • How can I change my all functions in program which do not take accept parameter to void myfunction(void) using code formatter tools like Astyle? Is there any option which I can give with astyle to change it for all the functions? – user7375520 Feb 04 '17 at 19:41
  • @user7375520 use gcc with `-Wstrict-prototypes` – ljrk Nov 03 '17 at 20:52
22

void foo(void) is better because it explicitly says: no parameters allowed.

void foo() means you could (under some compilers) send parameters, at least if this is the declaration of your function rather than its definition.

Uri
  • 84,589
  • 46
  • 214
  • 312
10

C99 quotes

This answer aims to quote and explain the relevant parts of the C99 N1256 standard draft.

Definition of declarator

The term declarator will come up a lot, so let's understand it.

From the language grammar, we find that the following underline characters are declarators:

int f(int x, int y);
    ^^^^^^^^^^^^^^^

int f(int x, int y) { return x + y; }
    ^^^^^^^^^^^^^^^

int f();
    ^^^

int f(x, y) int x; int y; { return x + y; }
    ^^^^^^^

Declarators are part of both function declarations and definitions.

There are 2 types of declarators:

  • parameter type list
  • identifier list

Parameter type list

Declarations look like:

int f(int x, int y);

Definitions look like:

int f(int x, int y) { return x + y; }

It is called parameter type list because we must give the type of each parameter.

Identifier list

Definitions look like:

int f(x, y)
    int x;
    int y;
{ return x + y; }

Declarations look like:

int g();

We cannot declare a function with a non-empty identifier list:

int g(x, y);

because 6.7.5.3 "Function declarators (including prototypes)" says:

3 An identifier list in a function declarator that is not part of a definition of that function shall be empty.

It is called identifier list because we only give the identifiers x and y on f(x, y), types come after.

This is an older method, and shouldn't be used anymore. 6.11.6 Function declarators says:

1 The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.

and the Introduction explains what is an obsolescent feature:

Certain features are obsolescent, which means that they may be considered for withdrawal in future revisions of this International Standard. They are retained because of their widespread use, but their use in new implementations (for implementation features) or new programs (for language [6.11] or library features [7.26]) is discouraged

f() vs f(void) for declarations

When you write just:

void f();

it is necessarily an identifier list declaration, because 6.7.5 "Declarators" says defines the grammar as:

direct-declarator:
    [...]
    direct-declarator ( parameter-type-list )
    direct-declarator ( identifier-list_opt )

so only the identifier-list version can be empty because it is optional (_opt).

direct-declarator is the only grammar node that defines the parenthesis (...) part of the declarator.

So how do we disambiguate and use the better parameter type list without parameters? 6.7.5.3 Function declarators (including prototypes) says:

10 The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters.

So:

void f(void);

is the way.

This is a magic syntax explicitly allowed, since we cannot use a void type argument in any other way:

void f(void v);
void f(int i, void);
void f(void, int);

What can happen if I use an f() declaration?

Maybe the code will compile just fine: 6.7.5.3 Function declarators (including prototypes):

14 The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.

So you can get away with:

void f();
void f(int x) {}

Other times, UB can creep up (and if you are lucky the compiler will tell you), and you will have a hard time figuring out why:

void f();
void f(float x) {}

See: Why does an empty declaration work for definitions with int arguments but not for float arguments?

f() and f(void) for definitions

f() {}

vs

f(void) {}

are similar, but not identical.

6.7.5.3 Function declarators (including prototypes) says:

14 An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.

which looks similar to the description of f(void).

But still... it seems that:

int f() { return 0; }
int main(void) { f(1); }

is conforming undefined behavior, while:

int f(void) { return 0; }
int main(void) { f(1); }

is non conforming as discussed at: Why does gcc allow arguments to be passed to a function defined to be with no arguments?

TODO understand exactly why. Has to do with being a prototype or not. Define prototype.

Community
  • 1
  • 1
  • From http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_317.htm I conclude that `void f() {}` is no [parameter] list and thus of course no empty list as required by 6.7.5.3 14. But then I do not know what would be an empty parameter list ... – ljrk Nov 03 '17 at 21:20
  • Okay, there's no such thing as an empty parameter-list. Ie. the empty list in the function declarator of a function definition specifies no arguments. However *compiling* this is not needing a diagnostic, since there's old K&R code that's defined that way. It *would be* UD however, if *all code paths* would boil down to somehow calling the function with wrong parameters (basically a run-time error). Calling a function with wrong parameters is only a compile-time error if either there's a prototype specifying the arguments or all code paths would be UD. – ljrk Nov 04 '17 at 11:58
4

Besides syntactical differences, many people also prefer using void function(void) for pracitical reasons:

If you're using the search function and want to find the implementation of the function, you can search for function(void), and it will return the prototype as well as the implementation.

If you omit the void, you have to search for function() and will therefore also find all function calls, making it more difficult to find the actual implementation.

maja
  • 14,242
  • 14
  • 72
  • 106
3

In C++, there is no difference in main() and main(void).

But in C, main() will be called with any number of parameters.

Example:

main ( ){
    main(10,"abc",12.28);
    //Works fine !
    //It won't give the error. The code will compile successfully.
    //(May cause Segmentation fault when run)
}

main(void) will be called without any parameters. If we try to pass then this end up leading to a compiler error.

Example:

main (void) {
     main(10,"abc",12.13);
     //This throws "error: too many arguments to function ‘main’ "
}
dlmeetei
  • 7,297
  • 3
  • 25
  • 34
Sandeep_black
  • 1,004
  • 12
  • 16