Two function declarations with void and empty argument list - c

I'd like to know why the following code:
void foo(void);
void foo()
{
}
is valid in gcc. In C, there is no such thing as overloading and above declarations (in fact, one of them is a definition) declare two different functions (the first one doesn't take any arguments, the second one could take any number of arguments of any types).
However, if we provide a definition for the first function:
void foo(void)
{
}
void foo()
{
}
a compilation fails this time due to redefinition. But still, the first code is correct and might be confusing as in the following:
void foo(void);
int main(void)
{
foo(); //OK
//foo(5); //Wrong, despite ->the definition<- allows it
}
void foo()
{
}
On the other hand, something like this is invalid straightaway:
void foo(int);
void foo() //error: number of arguments doesn't match prototype
{
}
I think the compiler's behavior is kinda weird in comparison to my first foregoing code. int isn't equal to (/*empty list*/) and neither is void.
Can anyone explain this ?

Quoting a late draft of the standard about function declarators:
(6.7.6.3/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.
(6.7.6.3/14) An identifier list declares only the identifiers of the
parameters of the function. An empty list in a function declarator
that is part of a definition of that function specifies that the
function has no parameters.
So the declarators of the declaration and definition are in fact compatible, and thus refer to the same function (with no overloading taking place of course, as such a thing does not exist in C.)

The line below is a function declaration, which tells the signature of the function foo: what is the type of the returned value and what are the types of the arguments.
void foo(void);
Below there is a function definition, which tells what does the function do. It does not overload anything. The definition and the declaration must match in the signature. void data type allows omitting it in the function definition.
void foo()
{
}
Since void is not an instantiable type (you cannot have a value of type void) it is OK to omit the arguments in the signature of the function's definition. However, if you try to do:
void foo(void*);
void foo() {
}
then you'll have a compile error because foo is expected to get a pointer to a don't-worry-about-type value.

C Standard defines for void as:-
The void type comprises an empty set of values; it is an incomplete
type that cannot be completed.
And the definition
void foo()
{
}
implies that the parameters are empty set of values which is valid for definition,so the gcc allows.
Also prototype for function declaration specifies:-
The special case of an unnamed parameter of type void as the only item
in the list specifies that the function has no parameters.

Related

Does C prefer a (void) arglist in a C function implementation? [duplicate]

void func()
In practice, an empty parameter means any argument is accepted.
void func(void) accepts no argument.
But in Standard C99, I find such lines:
6.7.5.3 Function declarators (including prototypes)
14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. 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.
According to the standard, are func() and func(void) the same?
TL;DR
In declarations,
void func1(); // obsolescent
void func2(void);
the behaviour is quite different. The first one declares a function without any prototype - and it may take any number of arguments! Whereas the latter declares a function with a prototype, that has no parameters and accepts no arguments.
In definitions
void func1() { } // obsolescent
and
void func2(void) { }
The former declares and defines a function func1 that has no parameters and no prototype
The latter declares and defines a function func2 with a prototype that has no parameters.
These two behave distinctly in that whereas the C compiler must print a diagnostic message when calling a prototyped function with wrong number of arguments, it needn't do so when calling a function without prototype.
I.e, given the definitions above
func1(1, 2, 3); // need not produce a diagnostic message
func2(1, 2, 3); // must always produce a diagnostic message
// as it is a constraint violation
However both calls are illegal in strictly-conforming programs as they're explicitly undefined behaviour as per 6.5.2.2p6.
Furthermore, the empty parentheses are considered an obsolescent feature:
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
and
The use of function definitions with separate parameter identifier and declaration lists (not prototype-format parameter type and identifier declarators) is an obsolescent feature.
In detail
There are 2 related, yet distinct concepts: parameters and arguments.
arguments are the values passed into the function.
parameters are the names/variables within the function that are set to the values of the arguments when the function entered
In the following excerpt:
int foo(int n, char c) {
...
}
...
foo(42, ch);
n and c are parameters. 42 and ch are arguments.
The quoted excerpt only concerns the parameters of a function, but doesn't mention anything about the prototype or arguments to the function.
The declaration void func1() means that the function func1 can be called with any number of arguments, i.e. no information about the number of arguments is specified (as a separate declaration, C99 specifies this as "function with no parameter specification), whereas the declaration void func2(void) means that the function func2 does not accept any arguments at all.
The quote in your question means that within a function definition, void func1() and void func2(void) both signal them that there are no parameters, i.e. variable names that are set to the values of the arguments when the function is entered. The void func() {} contrasts with void func(); the former declares that func indeed takes no parameters, whereas the latter is a declaration for a function func for which neither parameters nor their types are specified (a declaration without prototype).
However, they yet differ definition-wise in that
The definition void func1() {} doesn't declare a prototype, whereas void func2(void) {} does, because () is not a parameter type list, whereas (void) is a parameter type list (6.7.5.3.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.
and further 6.9.1.7
If the declarator includes a parameter type list, the
list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit. If the declarator includes an identifier list, the types of the parameters shall be declared in a following declaration list. In either case, the type of each parameter is adjusted as described in 6.7.5.3 for a parameter type list; the resulting type shall be an object type.
The declarator of function definition for func1 does not contain a parameter type list, and thus the function then doesn't have a prototype.
void func1() { ... } can still be called with any number of arguments, whereas it is a compile-time error to call void func2(void) { ... } with any arguments (6.5.2.2):
If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.
(emphasis mine)
This is a constraint, which according of the standard says that a conforming implementation must display at least one diagnostic message about this problem. But since func1 doesn't have a prototype, a conforming implementation is not required to produce any diagnostics.
However, if the number of arguments does not equal the number of parameters, the behaviour is undefined 6.5.2.2p6:
If the expression that denotes the called function has a type that does not include a prototype, [...] If the number of arguments does not equal the number of parameters, the behavior is undefined.
So in theory a conforming C99 compiler is also allowed to error or diagnose a warning in this case. StoryTeller provided evidence that clang might diagnose this; however, my GCC doesn't seem to do it (and this might also be required for it to be compatible with some old obscure code too):
void test() { }
void test2(void) { }
int main(void) {
test(1, 2);
test2(1, 2);
}
When the above program is compiled with gcc -std=c99 test.c -Wall -Werror, the output is:
test.c: In function ‘main’:
test.c:7:5: error: too many arguments to function ‘test2’
test2(1, 2);
^~~~~
test.c:3:6: note: declared here
void test2(void) { }
^~~~~
That is, the arguments are not checked at all against the parameters of a function whose declaration in definition is not prototyped (test) whereas GCC considers it as a compile-time error to specify any arguments to a prototyped function (test2); any conforming implementation must diagnose this as it is a constraint violation.
The significant part of the quote is highlighted in bold below:
6.7.5.3 Function declarators (including prototypes) 14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. 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, when the parameter list is empty for a function with its body, they are the same. But of it is just a declaration of a function.
void function1(); // No information about arguments
void function2(void); // Function with zero arguments
void function3() {
// Zero arguments
}
void function4(void) {
// Zero arguments
}
according to the standard, func() and func(void) is the same?
No. func(void) says the function takes no arguments at all; whereas func() says the function takes an unspecified number of arguments. Both are valid but the func() style are obsolete and shouldn't be used.
This is an artifact from pre-standard C. C99 marked this as obsolete.
6.11.6 Function declarators:
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
As of C11, it still remains as obsolescent and hasn't been removed from the standard.
The empty parameter list inside a function definition means that it does not include a prototype nor has any parameters.
C11 §6.9.1/7 Function definitions
(emphasis in ongoing quotes is mine)
The declarator in a function definition specifies the name of the
function being defined and the identifiers of its parameters. If the
declarator includes a parameter type list, the list also specifies the
types of all the parameters; such a declarator also serves as a
function prototype for later calls to the same function in the same
translation unit.
The question asks:
according to the standard, func() and func(void) is the same?
No. The essential difference between void func() and void func(void) lies in their calls.
C11 §6.5.2.2/2 Function calls (within constraints section):
If the expression that denotes the called function has a type that
includes a prototype, the number of arguments shall agree with the
number of parameters. Each argument shall have a type such that its
value may be assigned to an object with the unqualified version of the
type of its corresponding parameter.
Notice that parameters ≠ arguments. The function may contain no parameters, but it may have multiple arguments.
As a function defined with empty parameters does not introduce a prototype, it's not checked against its calls, so in theory it may be supplied with whatever number of arguments.
However, it is technically an undefined behavior (UB) to call such function with at least one argument (see Antti Haapala's comments).
C11 §6.5.2.2/6 Function calls (within semantics section):
If the number of arguments does not equal the number of parameters,
the behavior is undefined.
Hence, the difference is subtle:
When a function is defined with void, it won't compile when number of arguments don't match with parameters (along with their types), because of constraint violation (§6.5.2.2/2). Such a situation requires diagnostic message from a conforming compiler.
If it is defined with empty parameters, it may or may not compile (there is no requirement for a diagnostic message from a conforming compiler), however it's UB to call such function.
Example:
#include <stdio.h>
void func1(void) { puts("foo"); }
void func2() { puts("foo"); }
int main(void)
{
func1(1, 2); // constraint violation, it shouldn't compile
func2(3, 4); // may or may not compile, UB when called
return 0;
}
Note that an optimizing compiler may cut off the arguments in such a case. For instance, this is how Clang compiles the above code (excluding func1's call) with -01 on x86-64 according to the SysV ABI calling conventions:
main: # #main
push rax ; align stack to the 16-byte boundary
call func2 ; call func2 (no arguments given)
xor eax, eax ; set zero as return value
pop rcx ; restore previous stack position (RSP)
ret

What does "void fatal(char *); " mean?

I just started learning C, and I came across this in one of the example given, I know this is a function prototype, but the concept I am yet to wrap my head around is the fact that does
void function(char *);
mean when I finally declare the function, it is going take an argument char pointer argument like so
void function(char *arg){}
?
Just to answer the question you gave:
What does “void fatal(char *);” mean?
This is the prototype/declaration of the function fatal.fatal is a function, which takes a pointer to char as one and only argument.
void is the return type of the function, which in this case mean that the function does not return a value to its caller or if it does, the value returned is interpreted as invalid by the caller.
The prototype/declaration of the function fatal() is important for the compiler. In this way, primarily the compiler will get "known", how the function is later used in the following program but secondary also checks if there are any inconsistencies between the definition, declaration and the use of the function.
In C, You may omit a specific identifier for the pointer to char in the declaration of the function, but not in the definition. This a circumstance where C is different as C++; In C++ it is permissible to omit the identifier also in the definition. You can look at the respective phrases in the standards in this answer.
So in the definition of fatal in C you have to provide an identifier for the char pointer:
// Definition of function fatal().
void fatal(char *a)
{
printf("The string of (a) is: %s\n",a);
}
but you can omit this one in the declaration:
void fatal(char *);
Note: The identifier between the provided arguments, when calling the function and the parameters specified in the declaration of the function may vary, like:
// Declaration (Protoype) of function fatal().
void fatal(char* a); // parameter a (pointer to char);
int main()
{
char b[] = "Hello"; // Declaration and Initialization of array b.
printf("Let´s use the function fatal to print what the string in b is
contained of!\n");
fatal(b); // when given as argument to a function, b
// is a pointer to the first element of the char
// array of b.
}
// Definition of function fatal().
void fatal(char* a)
{
printf("The string of (a) is: %s\n",a);
}
See more about the difference between parameters and arguments here: What's the difference between an argument and a parameter?
In the more far view, there is also an important difference between "pass by value" and "pass by reference". A pointer argument/parameter is always a pass by reference. What these two especially are and how they distinct is best explained here: What's the difference between passing by reference vs. passing by value?
In this context and the context of scope visibility, it is also important to know if you have f.e. an identifier x which refers to an object in the function fatal, the same identifier of x can be used in the caller, and vice versa, to refer to a total different object in each scope. - Means, you can have the same identifier (name) for different objects in different scopes but each identifier can only used once in its scope.
Here void function(char *); is a function prototype which is simply the declaration of a function that specifies function's name, parameters and return type. It doesn't contain function body.
It gives information to the compiler that the function may later be used in the program.
It is not needed if the user-defined function is defined before the main() function.
does
[...] mean when I finally declare the function, it is going take an argument char pointer argument [...]
?
Yes, it does.
The important thing with the declaration of the function are the parameters' types. The parameters' names are not needed within the declaration
void function(char *);
but only within the function's definition
void function(char *arg)
{
}
.
It just informs the compiler what type parameters functions takes and what is the return type of it.
int main()
{
double x = foo(1,2);
}
void foo(double x)
{
printf("%f", x);
}
in this compiler does not know what parameters of the function foo are and how to pass them properly. Return type is also unknown. The compiler will assume they are int - which is not the truth in this case
https://godbolt.org/z/J8juc4

Why is this error not detected by compiler [duplicate]

void func()
In practice, an empty parameter means any argument is accepted.
void func(void) accepts no argument.
But in Standard C99, I find such lines:
6.7.5.3 Function declarators (including prototypes)
14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. 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.
According to the standard, are func() and func(void) the same?
TL;DR
In declarations,
void func1(); // obsolescent
void func2(void);
the behaviour is quite different. The first one declares a function without any prototype - and it may take any number of arguments! Whereas the latter declares a function with a prototype, that has no parameters and accepts no arguments.
In definitions
void func1() { } // obsolescent
and
void func2(void) { }
The former declares and defines a function func1 that has no parameters and no prototype
The latter declares and defines a function func2 with a prototype that has no parameters.
These two behave distinctly in that whereas the C compiler must print a diagnostic message when calling a prototyped function with wrong number of arguments, it needn't do so when calling a function without prototype.
I.e, given the definitions above
func1(1, 2, 3); // need not produce a diagnostic message
func2(1, 2, 3); // must always produce a diagnostic message
// as it is a constraint violation
However both calls are illegal in strictly-conforming programs as they're explicitly undefined behaviour as per 6.5.2.2p6.
Furthermore, the empty parentheses are considered an obsolescent feature:
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
and
The use of function definitions with separate parameter identifier and declaration lists (not prototype-format parameter type and identifier declarators) is an obsolescent feature.
In detail
There are 2 related, yet distinct concepts: parameters and arguments.
arguments are the values passed into the function.
parameters are the names/variables within the function that are set to the values of the arguments when the function entered
In the following excerpt:
int foo(int n, char c) {
...
}
...
foo(42, ch);
n and c are parameters. 42 and ch are arguments.
The quoted excerpt only concerns the parameters of a function, but doesn't mention anything about the prototype or arguments to the function.
The declaration void func1() means that the function func1 can be called with any number of arguments, i.e. no information about the number of arguments is specified (as a separate declaration, C99 specifies this as "function with no parameter specification), whereas the declaration void func2(void) means that the function func2 does not accept any arguments at all.
The quote in your question means that within a function definition, void func1() and void func2(void) both signal them that there are no parameters, i.e. variable names that are set to the values of the arguments when the function is entered. The void func() {} contrasts with void func(); the former declares that func indeed takes no parameters, whereas the latter is a declaration for a function func for which neither parameters nor their types are specified (a declaration without prototype).
However, they yet differ definition-wise in that
The definition void func1() {} doesn't declare a prototype, whereas void func2(void) {} does, because () is not a parameter type list, whereas (void) is a parameter type list (6.7.5.3.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.
and further 6.9.1.7
If the declarator includes a parameter type list, the
list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit. If the declarator includes an identifier list, the types of the parameters shall be declared in a following declaration list. In either case, the type of each parameter is adjusted as described in 6.7.5.3 for a parameter type list; the resulting type shall be an object type.
The declarator of function definition for func1 does not contain a parameter type list, and thus the function then doesn't have a prototype.
void func1() { ... } can still be called with any number of arguments, whereas it is a compile-time error to call void func2(void) { ... } with any arguments (6.5.2.2):
If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.
(emphasis mine)
This is a constraint, which according of the standard says that a conforming implementation must display at least one diagnostic message about this problem. But since func1 doesn't have a prototype, a conforming implementation is not required to produce any diagnostics.
However, if the number of arguments does not equal the number of parameters, the behaviour is undefined 6.5.2.2p6:
If the expression that denotes the called function has a type that does not include a prototype, [...] If the number of arguments does not equal the number of parameters, the behavior is undefined.
So in theory a conforming C99 compiler is also allowed to error or diagnose a warning in this case. StoryTeller provided evidence that clang might diagnose this; however, my GCC doesn't seem to do it (and this might also be required for it to be compatible with some old obscure code too):
void test() { }
void test2(void) { }
int main(void) {
test(1, 2);
test2(1, 2);
}
When the above program is compiled with gcc -std=c99 test.c -Wall -Werror, the output is:
test.c: In function ‘main’:
test.c:7:5: error: too many arguments to function ‘test2’
test2(1, 2);
^~~~~
test.c:3:6: note: declared here
void test2(void) { }
^~~~~
That is, the arguments are not checked at all against the parameters of a function whose declaration in definition is not prototyped (test) whereas GCC considers it as a compile-time error to specify any arguments to a prototyped function (test2); any conforming implementation must diagnose this as it is a constraint violation.
The significant part of the quote is highlighted in bold below:
6.7.5.3 Function declarators (including prototypes) 14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. 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, when the parameter list is empty for a function with its body, they are the same. But of it is just a declaration of a function.
void function1(); // No information about arguments
void function2(void); // Function with zero arguments
void function3() {
// Zero arguments
}
void function4(void) {
// Zero arguments
}
according to the standard, func() and func(void) is the same?
No. func(void) says the function takes no arguments at all; whereas func() says the function takes an unspecified number of arguments. Both are valid but the func() style are obsolete and shouldn't be used.
This is an artifact from pre-standard C. C99 marked this as obsolete.
6.11.6 Function declarators:
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
As of C11, it still remains as obsolescent and hasn't been removed from the standard.
The empty parameter list inside a function definition means that it does not include a prototype nor has any parameters.
C11 §6.9.1/7 Function definitions
(emphasis in ongoing quotes is mine)
The declarator in a function definition specifies the name of the
function being defined and the identifiers of its parameters. If the
declarator includes a parameter type list, the list also specifies the
types of all the parameters; such a declarator also serves as a
function prototype for later calls to the same function in the same
translation unit.
The question asks:
according to the standard, func() and func(void) is the same?
No. The essential difference between void func() and void func(void) lies in their calls.
C11 §6.5.2.2/2 Function calls (within constraints section):
If the expression that denotes the called function has a type that
includes a prototype, the number of arguments shall agree with the
number of parameters. Each argument shall have a type such that its
value may be assigned to an object with the unqualified version of the
type of its corresponding parameter.
Notice that parameters ≠ arguments. The function may contain no parameters, but it may have multiple arguments.
As a function defined with empty parameters does not introduce a prototype, it's not checked against its calls, so in theory it may be supplied with whatever number of arguments.
However, it is technically an undefined behavior (UB) to call such function with at least one argument (see Antti Haapala's comments).
C11 §6.5.2.2/6 Function calls (within semantics section):
If the number of arguments does not equal the number of parameters,
the behavior is undefined.
Hence, the difference is subtle:
When a function is defined with void, it won't compile when number of arguments don't match with parameters (along with their types), because of constraint violation (§6.5.2.2/2). Such a situation requires diagnostic message from a conforming compiler.
If it is defined with empty parameters, it may or may not compile (there is no requirement for a diagnostic message from a conforming compiler), however it's UB to call such function.
Example:
#include <stdio.h>
void func1(void) { puts("foo"); }
void func2() { puts("foo"); }
int main(void)
{
func1(1, 2); // constraint violation, it shouldn't compile
func2(3, 4); // may or may not compile, UB when called
return 0;
}
Note that an optimizing compiler may cut off the arguments in such a case. For instance, this is how Clang compiles the above code (excluding func1's call) with -01 on x86-64 according to the SysV ABI calling conventions:
main: # #main
push rax ; align stack to the 16-byte boundary
call func2 ; call func2 (no arguments given)
xor eax, eax ; set zero as return value
pop rcx ; restore previous stack position (RSP)
ret

What is the purpose of defining such a function?

int func (int,int);
int main ()
{
printf("hello");
}
Consider the above function. What is the purpose of defining functions like func? I have seen this repeatedly.
int func(int, int);
does not define a function, but declares it by providing its prototype. It's the "promise" to the compiler, that latest the linker will provide a module exposing such a function.
The prototype for a function covers its:
return type
name
the type and order of the arguments
The arguments' names are not relevant in the context of a declaration.
The function's arguments' names only need to be provided for the function's implementation, which might look like this:
int func(int a, int b)
{
return a + b;
}
On the other hand this
int func(int a, int)
{
return a;
}
is not valid.
The C Standard clearly states:
6.9.1/5 Function definitions
If the declarator includes a parameter type list, the declaration of each parameter shall
include an identifier, except for the special case of a parameter list consisting of a single
parameter of type void, in which case there shall not be an identifier. No declaration list
shall follow.
All the other answers are not answering the correct question explicitly, so I'm adding one here.
First of all, it's not a function definition because the body is missing. This semantic is called function declaration.
Before calling a function, the compiler needs to know what exactly the function is. This is named a "prototype". A prototype must be known before generating correct code to call a function. Consider this code:
// No previous info
int a = func(1, 3);
The compiler doesn't know if it is calling int func(int, int) or long func(char, double), nor can it perform error checking if the actual function is FILE* func(void*).
With a correct prototype privided, the compiler is able to perform necessary checking and generate the corresponding code of that function call.
It is not function defination but it is a functions declaration. A function declaration informs the compiler of the number of parameters the function has, the type of the function parameters and the type of the function return value.
1) It tells the return type of the data that the function will return.
2) It tells the number of arguments passed to the function.
3) It tells the data types of the each of the passed arguments.
4) Also it tells the order in which the arguments are passed to the
function.
5) It tells the name (identifier) of the function.
This is just a function declaration of a function to tell compiler that a function with name func exists having definition at end.
Consider this example:
#include<stdio.h>
int func (int,int);
int main()
{
printf("hello\n");
int c= func(5,4);
printf("%d\n",c);
}
int func(int a, int b)
{
return a+b;
}

Is it better to use C void arguments "void foo(void)" or not "void foo()"? [duplicate]

This question already has answers here:
Is there a difference between foo(void) and foo() in C++ or C?
(4 answers)
func() vs func(void) in C99
(4 answers)
Closed 5 years ago.
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?
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.
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.
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.
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.
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.
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 a segmentation fault when run)
}
main(void) will be called without any parameters. If we try to pass it then this ends up leading to a compiler error.
Example:
main (void) {
main(10, "abc", 12.13);
// This throws "error: too many arguments to function ‘main’ "
}

Resources