I've just come across someone's C code that I'm confused as to why it is compiling. There are two points I don't understand.
First, the function prototype has no parameters compared to the actual function definition. Second, the parameter in the function definition does not have a type.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
Why does this work? I have tested it in a couple of compilers, and it works fine.
Regarding parameter type, there are already correct answers here but if you want to hear it from the compiler you can try adding some flags (flags are almost always a good idea anyways).
compiling your program using
gcc foo.c -Wextra
I get:strangely
-Wextra
doesn't catch this forclang
(it doesn't recognize-Wmissing-parameter-type
for some reason, maybe for historical ones mentioned above) but-pedantic
does:And for prototype issue as said again above
int func()
refers to arbitrary parameters unless you exclicitly define it asint func(void)
which would then give you the errors as expected:or in
clang
as:int func();
is an obsolescent function declaration from the days when there was no C standard, i.e. the days of K&R C (before 1989, the year the first "ANSI C" standard was published).Remember that there were no prototypes in K&R C and the keyword
void
was not yet invented. All you could do was to tell the compiler about the return type of a function. The empty parameter list in K&R C means "an unspecified but fixed" number of arguments. Fixed means that you must call the function with the same number of args each time (as opposed to a variadic function likeprintf
, where the number and type can vary for each call).Many compilers will diagnose this construct; in particular
gcc -Wstrict-prototypes
will tell you "function declaration isn't a prototype", which is spot on, because it looks like a prototype (especially if you are poisoned by C++!), but isn't. It's an old style K&R C return type declaration.Rule of thumb: Never leave an empty parameter list declaration empty, use
int func(void)
to be specific. This turns the K&R return type declaration into a proper C89 prototype. Compilers are happy, developers are happy, static checkers are happy. Those mislead by^W^Wfond of C++ may cringe, though, because they need to type extra characters when they try to exercise their foreign language skills :-)This is why I typically advise people to compile their code with:
These flags enforce a couple of things:
These flags are also used by default in a lot of Open Source projects. For example, FreeBSD has these flags enabled when building with WARNS=6 in your Makefile.
All the other answers are correct, but just for completion
And again for the sake of completeness. From C11 specification 6:11:6 (page: 179)
In C
func()
means that you can pass any number of arguments. If you want no arguments then you have to declare asfunc(void)
. The type you're passing to your function, if not specified defaults toint
.As stated @Krishnabhadra, all previous responses from other users, have a correct interpretation, and I just want to make a more detailed analysis of some points.
In the Old-C as in ANSI-C the "untyped formal parameter", take the dimencion of your work register or instruction depth capability (shadow registers or instruction cumulative cycle), in an 8bit MPU, will be an int16, in a 16bit MPU and so will be an int16 an so on, in the case 64bit architectures may choose to compile options like: -m32.
Although it seems simpler implementation at high level, For pass multiple parameters, the work of the programmer in the control dimencion data type step, becomes more demanding.
In other cases, for some microprocessors architectures, the ANSI compilers customized, leveraged some of this old features to optimize the use of the code, forcing the location of these "untyped formal parameters" to work within or outside the work register, today you get almost the same with the use of "volatile" and "register".
But it should be noted that the most modern compilers, not make any distinction between the two types of parameters declaration.
Examples of a compilation with gcc under linux:
In any case the statement of the prototype locally is of no use, because there is no call without parameters reference to this prototype will be remiss. If you use the system with "untyped formal parameter", for an external call, proceed to generate a declarative prototype data type.
Like this: