6

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 ?

Quentin
  • 1,040
  • 10
  • 22

3 Answers3

12

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.)

eq-
  • 9,628
  • 34
  • 37
  • 2
    This is the answer: _An empty list in a function declarator that is part of a __definition__ of that function specifies that the function has no parameters._. If it would be the other way around, the declaration being `void foo();` and the definition `void foo(void) {}`, this would not hold. Your answer is the only one to actually note this difference. +1 – orlp Aug 18 '12 at 22:59
  • 1
    The 14th bullet actually continues to say what an empty list would mean for a declarator *not part of a definition*, for those that should care. – eq- Aug 18 '12 at 23:00
  • @eq- Well, if empty list in function definition specifies that the function doesn't take any parameters, then why does gcc allow something like this: `void f() {} //call: f(6, 7, 3.14) – Quentin Aug 19 '12 at 16:53
  • 1
    @Quentin, can't say for sure. Perhaps there's a bug in the compiler, or perhaps an earlier standard (than C11) had a different wording and GCC conforms to that (or perhaps it's me drawing wrong conclusions, who knows) – eq- Aug 19 '12 at 17:20
  • @eq- Alright, so in a nutshell, now `void f(void) {}` is just equivalent to `void f() {}`, yes? – Quentin Aug 19 '12 at 17:38
  • 2
    @Quentin, that seems to *not* be the case. My interpretation of the standard says that the two are identical *within the function* but only the former introduces a function prototype. This is compatible with the GCC behaviour you described earlier. The definitions are *compatible*, however (as I stated in the answer). – eq- Aug 27 '12 at 18:28
  • One key difference between `int function() { … }` and `int function(void) { … }` is that the first does not establish a prototype for the function. Even in the same file, a call such as `int j = function(i, 2, sin(x))` won't elicit a complaint about calling the function with the wrong number of parameters if the function is previously defined without `void` in the argument list. If the definition includes `void`, then the call is erroneous. – Jonathan Leffler Jun 29 '17 at 21:53
1

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.

Claudix
  • 4,755
  • 13
  • 27
  • The question is why it works since the signatures don't appear to be the same. – Antimony Aug 18 '12 at 22:47
  • Signatures match because `void` is not a instantiable data type. void holds nothing. However, if you put `void *` in the function declaration, it will raise a compile error if you don't put it too in the function definition. – Claudix Aug 18 '12 at 22:50
0

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.

BenMorel
  • 30,280
  • 40
  • 163
  • 285
perilbrain
  • 7,496
  • 1
  • 25
  • 35