The following code does not emit any warnings when compiled with both gcc
and clang
on Linux x64
:
#include <stdio.h>
#include <stdlib.h>
void foo(void);
void foo(void);
void foo(void);
int main(void)
{
return 0;
}
IMO, it's legal according to the following snippets from C99:
All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
(...)
For two function types to be compatible, both shall specify compatible return types
(...)
Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types.
(...)
Two types have compatible type if their types are the same.
Am I right? I want to make sure it is not UB and that my understanding is correct.
Multiple identical prototypes are legal, and in fact common, because it is typical in modern C for a function definition to comprise a prototype for that function, and for there also to be a prototype for the function in scope from inclusion of a header file. That is, given
foo.h:
void foo(int x);
foo.c:
#include "foo.h"
void foo(int x) {
printf("%d\n", x);
}
/* ... */
there are two identical prototypes for foo()
in scope in the body of function foo
's definition and throughout the rest of the file. This is fine.
It is also ok to have multiple declarations of the same object or function that are not identical, as long as they are compatible. For example, the declaration
void foo();
declares foo
as a function taking unspecified parameters and returning nothing. This declaration is compatible with the ones already present in foo.c
and foo.h
, and it could be added to either one or both of those files with zero additional effect.
And this all applies to objects (variables), too, where some applications are quite common. For example, if you want to declare a global variable that is accessed from multiple files, then it is common to put a declaration of that variable in a header file. The C source file containing and the definition of that variable -- which is also a declaration -- typically #include
s the header, yielding two declarations:
global.h:
extern int global;
global.c:
#include "global.h"
int global = 42;
Or there is the case of forward declaration of compound data types:
struct one;
struct two {
struct one *my_one;
struct two *next;
};
struct one {
struct two *my_two;
}
Note the multiple compatible, but not identical, declarations of struct one
. This particular set of data structures cannot be declared at all without multiple declaration of one of the types.
Addendum Re: C2X
C2X introduces a relevant change in this area: starting in that version of C, a function declaration that contains no parameter type list declares the function to take zero parameters, as in C++, whereas in previous versions of C, such a declaration provides no information about the number or type of parameters. Thus, in C2X and onward, a function declaration void foo()
is no longer compatible with void foo(int)
, as they specify different numbers of parameters.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With