I have noticed some behavior in C that I do not quite understand. If I define a function with an argument that I do not specify a type for and call it without any argument, the code compiles but gives a warning that the type of the parameter defaults to int.
void f(i) {
printf("%d", i);
}
int main(void) {
f();
}
If I run this on godbolt, I get the expected compiler warning, and execution prints 1 to stdout.
However, if I define the same method, but explicitly declare the argument as an int, the compiler throws an error for the function being called with too few arguments.
void f(int i) {
printf("%d", i);
}
int main(void) {
f();
}
Compiling this on godbolt produces error: too few arguments to function 'f'.
This behavior is consistent across all modern versions of gcc and clang. Why does specifying the type of the argument make this a compiler error? Also, is the behavior of the first example defined? The fact that gcc and clang both always make i 1 would make me think that this is intentional. If so, why?
The second piece of code is relatively simple. The function is defined to accept one argument, and the function call in main passed no arguments. That's a clear error.
The first piece of code is more interesting. This goes back to old style function definitions where the parameter list contains only the names of the parameters and the types appear between the closing parenthesis terminating the argument list and the opening brace before the start of the function body. Such a function properly defined would look like this:
void f(i)
int i;
{
printf("%d", i);
}
This style of specifying function arguments dates back to the original K&R C but is considered deprecated now. This variant of C also had the property that the type of a variable could be omitted in which cast it defaults to int.
However, even if you do specify the type after the argument list as in the above example, it's still not an error. So why is this?
The key parts comes from section 6.5.2.2 of the C standard regarding function calls:
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.
...
8 No other conversions are performed implicitly; in particular, the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator.
And section 6.9.1p7 regarding function definitions:
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. 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.6.3 for a parameter type list; the resulting type shall be a complete object type
In the case of a K&R style function definition, the parameters are specified as an identifier list as opposed to a parameter type list. This means that the function definition does not also specify a function prototype, meaning the number and types of the parameters are not checked when the function is called.
There are two types of function prototypes:
The original, known as "K&R" [from Kernighan & Ritchie, the creators of C].
The modern, known as "ANSI" [from the ANSI standardization committee].
At first, we only had K&R:
#include <stdio.h>
void
f(i)
int i;
{
printf("%d\n",i);
}
int
main(void)
{
f();
return 0;
}
When the C language was standardized, an alternate form of function prototype was added:
#include <stdio.h>
void
f(int i)
{
printf("%d\n",i);
}
int
main(void)
{
f();
return 0;
}
These are how the functions are defined. But, if we put f in a separate file, we'd be left with the prototype declarations:
Here is K&R:
#include <stdio.h>
void f();
int
main(void)
{
f();
return 0;
}
Here is ANSI:
#include <stdio.h>
void f(int i);
int
main(void)
{
f();
return 0;
}
If you look closely at the K&R prototype, there is no way to discern the type for i.
That blemish was rectified with ANSI. If you look at that prototype, the type is for i is explicitly specified as int.
So, to answer your question, in your examples, the syntax without the int is a K&R style prototype/definition. When we add int, it is an ANSI prototype/definition.
K&R hasn't been widely used in new code since sometime in the 1990's (IIRC). But, the compilers understand it for backward compatibility with code written pre-ANSI.
Side note: I started programming in C in 1981, so I was using K&R for at least a decade (A lot of this post comes from [fading] memory). After I got a compiler that supported ANSI, after a few months trying out the ANSI prototypes on new code, I converted all my old code to use ANSI.
For more information ...
See: Function declaration: K&R vs ANSI
And, Alternative (K&R) C syntax for function declaration versus prototypes
Related
I tried this program on DevC++ that would call two different types of function, one returning int and one returning char. I'm confused why the int function doesn't need a prototype, while the char one and any other type of function does.
#include <stdio.h>
//int function1();
char function2() ;
int main (){
int X = function1() ;
char Y = function2() ;
printf("%d", X) ;
printf ("%c", Y) ;
return 0 ;
}
int function1(){
return 100 ;
}
char function2(){
return 'B' ;
}
The output:
100B
If I remove the prototype for the char function, it results in:
[Error] conflicting types for 'function2'
[Note] previous implicit declaration of 'function2' was here
In the old days of C any function that was not declared explicitely was supposed to return int type when you call it.
If the compiler then finds the function implementation and sees an int return type, everything is fine.
If the function returns anything else than int you get the error message as you saw with the second function.
This implicit int type declaration was removed from the standard with C99. Now you should at least get a warning from your compiler when you use a function without prototype.
If you did not get any diagnostic message for first funcion, you should turn up warning level in your compiler or switch to at least C99 mode instead of ancient versions.
Edit:
Empty parameter lists in funcion definitions is a deprecated feature as well.
You should not use it.
Always provide prototype for every function with return type and parameter list.
If a function is used before it is declared, the usage becomes an implicit declaration of the function. When a function f is implicitly defined, the definition given to it is int f(), i.e. a function which accepts an unspecified number of arguments and returns an int.
This implicit definition of a function matches the actual definition of function1 but not function2. So calling function1 this way gives no error but attempting to call function2 this way results in the implicit definition not matching the actual definition, giving an error.
This behavior goes back to pre-standardized versions of C where all objects (and a function's return type) had a default type of int if not declared. This was still present in the C89 standard but removed in the C99 standard, although some compilers such as gcc still support this obsolescent usage as an extension.
It's just an ancient relic from when C was first designed. It was actually removed as early as C99, but many compilers still support this type of declaration. But it's not recommended to use it.
I'm not sure if there were any real rationale behind it, but C was heavily inspired by the language B. And in B you did not have to specify the return type for functions. That actually made perfect sense, because there was only one type, word.
In the same way you did not have to specify the type of variables either. You only specified if it had automatic or static storage. And that's where the completely useless keyword auto in C comes from. It does not mean the same as in C++. It just means "not static".
I know that “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„[1]:
// No information about the parameters is supplied.
int foo();
I know that “an empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters„[2].
// In this case the foo() function has no parameters.
int foo()
{
// ...
}
I know that “the special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters„[3]:
// foo() has no parameters.
int foo(void);
// bar() has no parameters.
int bar(void)
{
// ...
};
So here are some questions:
Is int main() { /* ... */ } legal? The standard states[4] that
The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent; or in some other implementation-defined manner.
So, is int main() { /* ... */ } is equivalent to int main(void) { /*... */ }?
Why GCC allows pass parameters to a function that has no parameters?
int foo();
int bar()
{
return 42;
}
int main(void)
{
// Should be OK.
foo(13);
// Should give a compile-time error.
bar(1, 12);
}
But I actually can compile the program with gcc version 10.1.0 (GCC): gcc -std=c17 -Werror -c test.c.
I've read some related questions, such as What are the valid signatures for C's main() function?, but they do not take into account the following standard clause[2]:
An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.
So, is my understanding of this clause correct?
ISO/IEC 9899:2017 § 6.7.6.3 / 14.
ISO/IEC 9899:2017 § 6.7.6.3 / 14.
ISO/IEC 9899:2017 § 6.7.6.3 / 10.
ISO/IEC 9899:2017 § 5.1.2.2.1 / 1.
Per the letter of the standard, yes. 5.1.2.2.1 says "[main] shall be defined with a return type of int[,] and with no parameters, or with two parameters [...]". int main() {} is a definition with return type int and no parameters, and 5.1.2.2.1 does not say anywhere that the definition is required to be prototyped.
(The code fragment shown immediately after "and with no parameters" may appear to be making a requirement to write (void), but all code fragments are considered to be examples, and therefore non-normative. It doesn't actually say this anywhere in the text, but it has come up in DR responses at least a couple times; I regret I do not remember specific numbers, it was more than 15 years ago now.)
However, because of (2), you should write int main(void) anyway.
Section 6.5.2.2 (semantics of function calls), paragraph 8, says "the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator." However, paragraph 6 of the same section says that in the event of an actual mismatch between the definition and the callsite the behavior is undefined. That means, compilers are allowed to issue an error when a function defined as T foo() {} is called with arguments, but it also means they are allowed not to issue an error.
For the sake of backward compatibility with pre-C89 code, which regularly did make function calls with a mismatched number of arguments, many compilers will accept such code without complaint. I have seen this behavior with Clang and MSVC as well as GCC. Newer versions of Clang do give you a warning:
$ clang --version | head -1
clang version 9.0.1-13
$ clang test.c
test.c:14:14: warning: too many arguments in call to 'bar'
bar(1, 12);
~~~ ^
I don't know how long this warning's been on by default.
Someone ought to go through all of GCC's intentional leniences for the sake of backward compatibility with really old code, and turn many of them off by default, but nobody's interested in funding this so it probably won't ever happen.
This standard is vague on this. It does not really define what "or equivalent" means. However you may want to know that the standard uses int main() in at least one code example. Code examples are not normative though.
The call site doesn't see a definition. It only sees a declaration. The (draft document N2176) standard says
[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.
A declarator without a parameter type list does not serve as a function prototype for later calls, even if it is a part of a definition.
[6.5.2.2/8] the number and types of arguments are
not compared with those of the parameters in a function definition that does not include a function prototype declarator.
In this example i'm getting a Conflicting types error as expected:
#include <stdio.h>
int a(int b);
int a(int *b){
return 6;
}
int main(){
return 0;
}
But not in this example:
#include <stdio.h>
int a(int b);
int a(){
return 6;
}
int main(){
return 0;
}
Why the second example is compiling fine although the declaration and definition and of a are still different?
Overview and History
Due to the history of how the C language developed, int a() does not mean “a takes no arguments and returns an int.” It means “a takes unspecified arguments and returns an int.”
Since “unspecified arguments” is nominally compatible with “one argument that is an int,” the compiler does not give an error for conflicting types. Due to further rules in C (see “Function Compatibility” below), the types are incompatible, but the compiler is not required to diagnose this.
Originally in C, functions were declared with a parameter list of (), and it was up to the caller to provide the correct types. (In addition, arguments were “promoted”; char arguments were converted to int, and so on, but this is a separate issue.) Where a function was defined, it was defined with names of parameters, such as int a(b), and the declarations of those parameters followed, as in:
int a()
int b;
{
return 6*b;
}
But that was only for the definition. The declaration did not have those declarations of the parameter types.
Later, to improve the type information about functions, C added grammar for full declarations of functions including parameter types, such as int a(int b). However, since the old grammar was already using int a() to mean “unspecified parameters,” the language had to keep that meaning to support old code.
Instead, a special form was designated to mean “no parameters,” and that is to put void by itself in the parameter list. int a(void) means “a is a function taking no parameters and returning int.” So, if you declare a function as int a(void); and then define it with int a(int b) { … }, the compiler will give you an error message.
Function Compatibility
One of the rules for function types to be compatible in C 2018 6.7.6.3 15 says:
… If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters,…
The declaration int a(int b); has a parameter type list with one parameter.
This definition:
int a(){
return 6;
}
has an empty identifier list and, between the int a() and the {, defines no parameters. So they do not agree in the number of parameters. However, the compiler is not required to diagnose this incompatibility.
Because in C (but not C++), a() declares a function with an unspecified number of parameters. Use a(void) instead.
See C function with no parameters behavior
Second example:
int a(){
a is a function taking unspecified number of parameters. So any number is fine and thus no error.
It is a compiler defect.
According to the C Standard (6.7.6.3 Function declarators (including prototypes))
...If one type has a parameter type list and the other type is specified
by a function definition that contains a (possibly empty) identifier
list, both shall agree in the number of parameters, and the type of
each prototype parameter shall be compatible with the type that
results from the application of the default argument promotions to the
type of the corresponding identifier
So as in these declarations
int a(int b);
int a(){
return 6;
}
the number of parameters differs for the functions the compiler shall issue a message because the name a is used to declare two different functions.
For example running this code using gcc 8.3 you can get the following errors
prog.c: In function ‘a’:
prog.c:5:1: error: number of arguments doesn’t match prototype
int a(){
^~~
prog.c:3:5: error: prototype declaration
int a(int b);
^
This question already has answers here:
What does an empty parameter list mean? [duplicate]
(5 answers)
Accessing the parameters passed to a function with an empty parameter list in C
(2 answers)
Closed 2 years ago.
I have been reading the difference between function() and function(void) in C, and I came to know that
an empty parameter list in a function declaration indicates that the
function takes an unspecified number of parameters
So I ran this code:
#include <stdio.h>
void fun();
int main(void)
{
fun(12, 13.22, 1234567890987654321, "wow", 'c');
}
void fun()
{
printf("What happened to those arguments?");
}
I don't understand why C allows this. All the posts I've read so far related to this say things like it's bad practice to use it, it is obsolescent, etc. Also from the above code, I think the type of those arguments is also unspecified. So I just want to know the reason behind "unspecified arguments of unspecified type":
What can be done with those arguments?
Is it possible to access those arguments within the function?
The reason for supporting the notation is historical. Before the first C standard (C89/C90), you couldn't use prototypes in C; prototypes were one of the biggest and most important features of Standard C. All function declarations, therefore, were written the 'empty parentheses' style (when they were written at all; most functions that returned int were not declared at all). The type void was also added in C89/C90, though some compilers supported it before the standard was finalized.
Because it was crucial to the success of C89/C90 that existing code should mostly continue to work, the empty parentheses style had to be allowed by the standard. So, your code might have been written in pre-standard C as:
#include <stdio.h>
int fun(); /* This declaration would probably have been absent */
int main(void)
{
fun(12, 13.22, 1234567, "wow", 'c');
return 0; /* This was required until C99 to give reliable exit status */
}
fun(i, d, l, s, c) /* No return type - implicitly returns int */
long l; /* Defined out of sequence - bad style, but legal */
char c; /* Passed as int; converted to char in function */
char *s; /* Should define all pointer arguments */
double d; /* No definition of i; it was an int by default */
{
printf("This is what happened to those arguments:\n");
printf("i = %d\n", i);
printf("d = %f\n", d);
printf("l = %ld\n", l);
printf("s = [%s]\n", s);
printf("c = %c\n", c);
/* No return statement - don't use the value from the function */
}
For the curious: you could omit the char *s; line in the function definition, and it still compiled and produced the same output. It was a bad idea to try that, though. You could replace the line int fun(); with static fun(); and the code compiles cleanly when no diagnostics are requested.
You get no warnings even now if you compile this file (old31.c) with GCC 9.3.0 using:
$ gcc -std=c90 -o old31 old31.c
$
Your example as written is skirting around the backwards compatibility provisions. Using void means it was new code (it would not have been valid in many pre-standard C compilers because it used void). And new code should not exploit the backwards-compatibility provisions without a good reason. That was true in 1991 as well as in the current millennium (but in 1991, there were a lot more good reasons to exploit the backwards-compatibility provisions). Good pre-standard code usually listed all parameters in the order they were used. Omitted definitions and out of sequence definitions were not entirely satisfactory.
You asked:
What can be done with those arguments?
In the code in the question, nothing can be done with the arguments. The caller pushes the values onto the stack, and pops them off when the function returns. The called function is unaware of their existence and can do nothing with them.
Is it possible to access those arguments within the function?
No — not using any standard mechanism.
There is a difference between a function declaration and a function definition when there is an empty parameter list.
Section 6.7.6.3p14 of the C standard states:
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.
What this means is that this declaration:
void fun();
Means fun takes an unknown number of parameters. While this definition:
void fun()
{
printf("What happened to those arguments?");
}
Means that fun takes no parameters. So this function call:
fun(12, 13.22, 1234567890987654321, "wow", 'c');
Is invalid and invoked undefined behavior because the number of parameters in the call don't match the actual number of parameters. This is spelled out in section 6.5.2.2p6 regarding the function call operator ():
If the expression that denotes the called function has a
type that does not include a prototype, the integer promotions
are performed on each argument, and arguments that have
type float are promoted to double. These are called the default
argument promotions. If the number of arguments does not equal
the number of parameters, the behavior is undefined. If the
function is defined with a type that includes a prototype, and either
the prototype ends with an ellipsis (, ...) or the types of
the arguments after promotion are not compatible with the types of
the parameters, the behavior is undefined.If the function is
defined with a type that does not include a prototype, and
the types of the arguments after promotion are not compatible
with those of the parameters after promotion, the behavior is
undefined, except for the following cases:
one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type,
and the value is representable in both types;
both types are pointers to qualified or unqualified versions of a character type or void.
As for why this is allowed, it is legacy behavior that goes back to pre-standardized versions of C where the type of variables and the return type of functions defaulted to int and the method of declaring functions differed from what they are now.
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.
The function prototype has no parameters compared to the actual function definition.
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.
All the other answers are correct, but just for completion
A function is declared in the following manner:
return-type function-name(parameter-list,...) { body... }
return-type is the variable type that the function returns. This can not be an array type or a function type. If not given, then int
is assumed.
function-name is the name of the function.
parameter-list is the list of parameters that the function takes separated by commas. If no parameters are given, then the function
does not take any and should be defined with an empty set of
parenthesis or with the keyword void. If no variable type is in front
of a variable in the paramater list, then int is assumed. Arrays and
functions are not passed to functions, but are automatically converted
to pointers. If the list is terminated with an ellipsis (,...), then
there is no set number of parameters. Note: the header stdarg.h can be
used to access arguments when using an ellipsis.
And again for the sake of completeness. From C11 specification 6:11:6 (page: 179)
The use of function declarators with empty parentheses (not
prototype-format parameter type declarators) is an obsolescent
feature.
In C func() means that you can pass any number of arguments. If you want no arguments then you have to declare as func(void). The type you're passing to your function, if not specified defaults to int.
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 like printf, 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 :-)
The empty parameter list means "any arguments", so the definition isn't wrong.
The missing type is assumed to be int.
I would consider any build that passes this to be lacking in configured warning/error level though, there's no point in being this allowing for actual code.
It's K&R style function declaration and definition. From C99 Standard (ISO/IEC 9899:TC3)
Section 6.7.5.3 Function Declarators (including prototypes)
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. (If both function types are "old style", parameter types are not compared.)
Section 6.11.6 Function declarators
The use of function declarators with empty parentheses (not prototype-format parameter
type declarators) is an obsolescent feature.
Section 6.11.7 Function definitions
The use of function definitions with separate parameter identifier and declaration lists
(not prototype-format parameter type and identifier declarators) is an obsolescent feature.
Which the old style means K&R style
Example:
Declaration: int old_style();
Definition:
int old_style(a, b)
int a;
int b;
{
/* something to do */
}
C assumes int if no type is given on function return type and parameter list. Only for this rule following weird things are possible.
A function definition looks like this.
int func(int param) { /* body */}
If its a prototype you write
int func(int param);
In prototype you can only specify the type of parameters. Parameters' name is not mandatory. So
int func(int);
Also if you dont specify parameter type but name int is assumed as type.
int func(param);
If you go farther, following works too.
func();
Compiler assumes int func() when you write func(). But dont put func() inside a function body. That'll be a function call
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:
int myfunc(int param);
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:
foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
strangely -Wextra doesn't catch this for clang (it doesn't recognize -Wmissing-parameter-type for some reason, maybe for historical ones mentioned above) but -pedantic does:
foo.c:5:10: warning: parameter 'param' was not declared,
defaulting to type 'int' [-pedantic]
int func(param)
^
1 warning generated.
And for prototype issue as said again above int func() refers to arbitrary parameters unless you exclicitly define it as int func(void) which would then give you the errors as expected:
foo.c: In function ‘func’:
foo.c:6:1: error: number of arguments doesn’t match prototype
foo.c:3:5: error: prototype declaration
foo.c: In function ‘main’:
foo.c:12:5: error: too many arguments to function ‘func’
foo.c:5:5: note: declared here
or in clang as:
foo.c:5:5: error: conflicting types for 'func'
int func(param)
^
foo.c:3:5: note: previous declaration is here
int func(void);
^
foo.c:12:20: error: too many arguments to function call, expected 0, have 1
int bla = func(10);
~~~~ ^~
foo.c:3:1: note: 'func' declared here
int func(void);
^
2 errors generated.
If the function declaration has no parameters i.e. empty then it is taking unspecified number of arguments. If you want to make it take no arguments then change it to:
int func(void);
This is why I typically advise people to compile their code with:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
These flags enforce a couple of things:
-Wmissing-variable-declarations: It is impossible to declare a non-static function without getting a prototype first. This makes it more likely that a prototype in a header file matches with the actual definition. Alternatively, it enforces that you add the static keyword to functions that don't need to be visible publicly.
-Wstrict-variable-declarations: The prototype must properly list the arguments.
-Wold-style-definition: The function definition itself must also properly list the arguments.
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.
In the old-style declarator,
the identifier list must be absent unless
the declarator is used in the head of a function definition
(Par.A.10.1). No information about the types of the parameters is
supplied by the declaration. For example, the declaration
int f(), *fpi(), (*pfi)();
declares a function f returning an integer, a function fpi returning a pointer to an integer, >and a pointer pfi to a function returning an integer. In none of these are the parameter types >specified; they are old-style.
In the new-style declaration
int strcpy(char *dest, const char *source), rand(void);
strcpy is a
function returning int, with two arguments, the first a character
pointer, and the second a pointer to constant characters
SOURCE:- K&R book
I hope it cleared your doubt..