I'm not familiar with K&R style function declaration.
Following compiles, with warning (just related to return value of main that too with -Wall) but what are the data types of variables used ?
main(a, b, c, d){
printf("%d", d);
}
foo(a, b){
a = 2;
b = 'z';
}
If this is a asked before please provide the link in comment section. I couldn't find something similar.
Edit
I just came across an obfuscated C code, which uses these.
But I can assure you, I won't be using such syntax in C programming.
"K&R C" refers to the language defined by the 1978 first edition of Kernighan & Ritchie's book "The C Programming Language".
In K&R (i.e., pre-ANSI) C, entities could commonly be declared without an explicit type, and would default to type int. This goes back to C's ancestor languages, B and BCPL.
main(a,b,c,d){
printf("%d", d);
}
That's nearly equivalent to:
int main(int a, int b, int c, int d) {
printf("%d", d);
}
The old syntax remained legal but obsolescent in ANSI C (1989) and ISO C (1990), but the 1999 ISO C standard dropped the "implicit int" rule (while keeping the old-style declaration and definition syntax).
Note that I said it's nearly equivalent. It's essentially the same when viewed as a definition, but as a declaration it doesn't provide parameter type information. With the old-style definition, a call with the wrong number or types of arguments needn't be diagnosed; it's just undefined behavior. With a visible prototype, mismatched arguments trigger a compile-time diagnostic -- and, when possible, arguments are implicitly converted to the parameter type.
And since this is a definition of main, there's another problem. The standard only specifies two forms for main (one with no arguments and one with two arguments, argc and argv). An implementation may support other forms, but one with four int arguments isn't likely to be one of them. The program's behavior is therefore undefined. In practice, it's likely that d will have some garbage value on the initial call. (And yes, a recursive call to main is permitted in C, but hardly ever a good idea.)
foo(a,b){
a = 2;
b = 'z';
}
This is nearly equivalent to:
int foo(int a, int b) {
a = 2;
b = 'z';
}
(And note that 'z' is of type int, not of type char.)
And again, the old form doesn't give you parameter type checking, so a call like:
foo("wrong type and number of arguments", 1.5, &foo);
needn't be diagnosed.
The bottom line: It's good to know how K&R-style function declarations and definitions work. There's still old code that uses them, and they're still legal (but obsolescent) even in C2011 (though without the "implicit int" rule). But there is very nearly no good reason to write code that uses them (unless you're stuck using a very old compiler, but that's rare and becoming rarer.)
But I can assure you, I won't be using such syntax in C programming.
Excellent!
In K&R style function definition the type of the parameter is specified by a dedicated set of declarations that is placed between the function "signature" itself and the actual function body. For example, this function definition
void foo(a, b, c)
double a;
char b;
{
...
}
uses parameters of type double, char and int. This is actually where and how the "implicit int" rule comes into play: since parameter c was not mentioned by the above declaration list, it is assumed to have type int.
Note the important detail, which I believe is not made clear enough by other answers: parameter c has type int not because the type is missing in function parameter list, but rather because it is not mentioned in the sequence of declarators that follows the function "signature" (before the function body). In K&R-style declarations types are always missing from function parameter list (that's the defining feature of K&R declaration), yet it does not immediately mean that all parameters are assumed to have type int.
P.S. Note that C99 still supports K&R style declarations, but since C99 outlawed the "implicit int" rule, it requires you to mention all function parameters in that declaration list after the function "signature". The above example will not compile in C99 for that reason. int c has to be added to the declaration list.
The default parameter is of int type in C and about K & R syntax please have a look here and here.
In C89, the default variable type is int: it is defined as implicit int. This rule has been revoked in C99.
In your example, it is compiled as:
main(int a,int b,int c,int d){printf("%d", d);}
foo(int a,int b){a=2; b='z';}
Related
What is useful about this C syntax — using 'K&R' style function declarations?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
I was able to write this in Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
I don't understand. What's the point of this syntax? I can write:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
The only thing it seems to specify is how many parameters it uses and the return type. I guess parameters without types is kind of cool, but why allow it and the int paranName after the function declarator? It's weird.
Also is this still standard C?
The question you are asking is really two questions, not one. Most replies so far tried to cover the entire thing with a generic blanket "this is K&R style" answer, while in fact only a small part of it has anything to do with what is known as K&R style (unless you see the entire C language as "K&R-style" in one way or another :)
The first part is the strange syntax used in function definition
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
This one is actually a K&R-style function definition. Other answer have covered this pretty well. And there's not much to it, actually. The syntax is deprecated, but still fully supported even in C99 (except for "no implicit int" rule in C99, meaning that in C99 you can't omit the declaration of p2).
The second part has little to do with K&R-style. I refer to the fact that the function can be called with "swapped" arguments, i.e. no parameter type checking takes place in such a call. This has very little to do with K&R-style definition per se, but it has everything to do with your function having no prototype. You see, in C when you declare a function like this
int foo();
it actually declares a function foo that takes an unspecified number of parameters of unknown type. You can call it as
foo(2, 3);
and as
j = foo(p, -3, "hello world");
ans so on (you get the idea);
Only the call with proper arguments will "work" (meaning that the others produce undefined behavior), but it is entirely up to you to ensure its correctness. The compiler is not required to diagnose the incorrect ones even if it somehow magically knows the correct parameter types and their total number.
Actually, this behavior is a feature of C language. A dangerous one, but a feature nevertheless. It allows you to do something like this
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
i.e. mix different function types in a "polymorphic" array without any typecasts (variadic function types can't be used here though). Again, inherent dangers of this technique are quite obvious (I don't remember ever using it, but I can imagine where it can be useful), but that's C after all.
Finally, the bit that links the second part of the answer to the first. When you make a K&R-style function definition, it doesn't introduce a prototype for the function. As far as function type is concerned, your func definition declares func as
int func();
i.e. neither the types nor the total number of parameters are declared. In your original post you say "... it seems to specify is how many params it uses ...". Formally speaking, it doesn't! After your two-parameter K&R-style func definition you still can call func as
func(1, 2, 3, 4, "Hi!");
and there won't be any constraint violation in it. (Normally, a quality compiler will give you a warning).
Also, a sometimes overlooked fact is that
int f()
{
return 0;
}
is also a K&R-style function definition that does not introduce a prototype. To make it "modern" you'd have to put an explicit void in the parameter list
int f(void)
{
return 0;
}
Finally, contrary to a popular belief, both K&R-style function definitions and non-prototyped function declarations are fully supported in C99. The former has been deprecated since C89/90, if I remember correctly. C99 requires the function to be declared before the first use, but the declaration is not required to be a prototype. The confusion apparently stems from the popular terminological mix-up: many people call any function declaration "a prototype", while in fact "function declaration" is not the same thing as "prototype".
This is pretty old K&R C syntax (pre-dates ANSI/ISO C). Nowadays, you should not use it anymore (as you have already noticed its major disadvantage: the compiler won't check the types of arguments for you). The argument type actually defaults to int in your example.
At the time, this syntax was used, one sometimes would find functions like
foo(p, q)
{
return q + p;
}
which was actually a valid definition, as the types for p, q, and the return type of foo default to int.
This is simply an old syntax, that pre-dates the "ANSI C" syntax you might be more familiar with. It's called "K&R C", typically.
Compilers support it to be complete, and to be able to handle old code bases, of course.
This is the original K&R syntax before C was standardized in 1989. C89 introduced function prototypes, borrowed from C++, and deprecated the K&R syntax. There is no reason to use it (and plenty of reasons not to) in new code.
That's a relic from when C had no prototypes for functions. Way back then, (I think) functions were assumed to return int and all its arguments were assumed to be int. There was no checking done on function parameters.
You're much better off using function prototypes in the current C language.
And you must use them in C99 (C89 still accepts the old syntax).
And C99 requires functions to be declared (possibly without a prototype). If you're writing a new function from scratch, you need to provide a declaration ... make it a prototype too: you lose nothing and gain extra checking from the compiler.
What is useful about this C syntax — using 'K&R' style function declarations?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
I was able to write this in Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
I don't understand. What's the point of this syntax? I can write:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
The only thing it seems to specify is how many parameters it uses and the return type. I guess parameters without types is kind of cool, but why allow it and the int paranName after the function declarator? It's weird.
Also is this still standard C?
The question you are asking is really two questions, not one. Most replies so far tried to cover the entire thing with a generic blanket "this is K&R style" answer, while in fact only a small part of it has anything to do with what is known as K&R style (unless you see the entire C language as "K&R-style" in one way or another :)
The first part is the strange syntax used in function definition
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
This one is actually a K&R-style function definition. Other answer have covered this pretty well. And there's not much to it, actually. The syntax is deprecated, but still fully supported even in C99 (except for "no implicit int" rule in C99, meaning that in C99 you can't omit the declaration of p2).
The second part has little to do with K&R-style. I refer to the fact that the function can be called with "swapped" arguments, i.e. no parameter type checking takes place in such a call. This has very little to do with K&R-style definition per se, but it has everything to do with your function having no prototype. You see, in C when you declare a function like this
int foo();
it actually declares a function foo that takes an unspecified number of parameters of unknown type. You can call it as
foo(2, 3);
and as
j = foo(p, -3, "hello world");
ans so on (you get the idea);
Only the call with proper arguments will "work" (meaning that the others produce undefined behavior), but it is entirely up to you to ensure its correctness. The compiler is not required to diagnose the incorrect ones even if it somehow magically knows the correct parameter types and their total number.
Actually, this behavior is a feature of C language. A dangerous one, but a feature nevertheless. It allows you to do something like this
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
i.e. mix different function types in a "polymorphic" array without any typecasts (variadic function types can't be used here though). Again, inherent dangers of this technique are quite obvious (I don't remember ever using it, but I can imagine where it can be useful), but that's C after all.
Finally, the bit that links the second part of the answer to the first. When you make a K&R-style function definition, it doesn't introduce a prototype for the function. As far as function type is concerned, your func definition declares func as
int func();
i.e. neither the types nor the total number of parameters are declared. In your original post you say "... it seems to specify is how many params it uses ...". Formally speaking, it doesn't! After your two-parameter K&R-style func definition you still can call func as
func(1, 2, 3, 4, "Hi!");
and there won't be any constraint violation in it. (Normally, a quality compiler will give you a warning).
Also, a sometimes overlooked fact is that
int f()
{
return 0;
}
is also a K&R-style function definition that does not introduce a prototype. To make it "modern" you'd have to put an explicit void in the parameter list
int f(void)
{
return 0;
}
Finally, contrary to a popular belief, both K&R-style function definitions and non-prototyped function declarations are fully supported in C99. The former has been deprecated since C89/90, if I remember correctly. C99 requires the function to be declared before the first use, but the declaration is not required to be a prototype. The confusion apparently stems from the popular terminological mix-up: many people call any function declaration "a prototype", while in fact "function declaration" is not the same thing as "prototype".
This is pretty old K&R C syntax (pre-dates ANSI/ISO C). Nowadays, you should not use it anymore (as you have already noticed its major disadvantage: the compiler won't check the types of arguments for you). The argument type actually defaults to int in your example.
At the time, this syntax was used, one sometimes would find functions like
foo(p, q)
{
return q + p;
}
which was actually a valid definition, as the types for p, q, and the return type of foo default to int.
This is simply an old syntax, that pre-dates the "ANSI C" syntax you might be more familiar with. It's called "K&R C", typically.
Compilers support it to be complete, and to be able to handle old code bases, of course.
This is the original K&R syntax before C was standardized in 1989. C89 introduced function prototypes, borrowed from C++, and deprecated the K&R syntax. There is no reason to use it (and plenty of reasons not to) in new code.
That's a relic from when C had no prototypes for functions. Way back then, (I think) functions were assumed to return int and all its arguments were assumed to be int. There was no checking done on function parameters.
You're much better off using function prototypes in the current C language.
And you must use them in C99 (C89 still accepts the old syntax).
And C99 requires functions to be declared (possibly without a prototype). If you're writing a new function from scratch, you need to provide a declaration ... make it a prototype too: you lose nothing and gain extra checking from the compiler.
What is useful about this C syntax — using 'K&R' style function declarations?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
I was able to write this in Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
I don't understand. What's the point of this syntax? I can write:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
The only thing it seems to specify is how many parameters it uses and the return type. I guess parameters without types is kind of cool, but why allow it and the int paranName after the function declarator? It's weird.
Also is this still standard C?
The question you are asking is really two questions, not one. Most replies so far tried to cover the entire thing with a generic blanket "this is K&R style" answer, while in fact only a small part of it has anything to do with what is known as K&R style (unless you see the entire C language as "K&R-style" in one way or another :)
The first part is the strange syntax used in function definition
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
This one is actually a K&R-style function definition. Other answer have covered this pretty well. And there's not much to it, actually. The syntax is deprecated, but still fully supported even in C99 (except for "no implicit int" rule in C99, meaning that in C99 you can't omit the declaration of p2).
The second part has little to do with K&R-style. I refer to the fact that the function can be called with "swapped" arguments, i.e. no parameter type checking takes place in such a call. This has very little to do with K&R-style definition per se, but it has everything to do with your function having no prototype. You see, in C when you declare a function like this
int foo();
it actually declares a function foo that takes an unspecified number of parameters of unknown type. You can call it as
foo(2, 3);
and as
j = foo(p, -3, "hello world");
ans so on (you get the idea);
Only the call with proper arguments will "work" (meaning that the others produce undefined behavior), but it is entirely up to you to ensure its correctness. The compiler is not required to diagnose the incorrect ones even if it somehow magically knows the correct parameter types and their total number.
Actually, this behavior is a feature of C language. A dangerous one, but a feature nevertheless. It allows you to do something like this
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
i.e. mix different function types in a "polymorphic" array without any typecasts (variadic function types can't be used here though). Again, inherent dangers of this technique are quite obvious (I don't remember ever using it, but I can imagine where it can be useful), but that's C after all.
Finally, the bit that links the second part of the answer to the first. When you make a K&R-style function definition, it doesn't introduce a prototype for the function. As far as function type is concerned, your func definition declares func as
int func();
i.e. neither the types nor the total number of parameters are declared. In your original post you say "... it seems to specify is how many params it uses ...". Formally speaking, it doesn't! After your two-parameter K&R-style func definition you still can call func as
func(1, 2, 3, 4, "Hi!");
and there won't be any constraint violation in it. (Normally, a quality compiler will give you a warning).
Also, a sometimes overlooked fact is that
int f()
{
return 0;
}
is also a K&R-style function definition that does not introduce a prototype. To make it "modern" you'd have to put an explicit void in the parameter list
int f(void)
{
return 0;
}
Finally, contrary to a popular belief, both K&R-style function definitions and non-prototyped function declarations are fully supported in C99. The former has been deprecated since C89/90, if I remember correctly. C99 requires the function to be declared before the first use, but the declaration is not required to be a prototype. The confusion apparently stems from the popular terminological mix-up: many people call any function declaration "a prototype", while in fact "function declaration" is not the same thing as "prototype".
This is pretty old K&R C syntax (pre-dates ANSI/ISO C). Nowadays, you should not use it anymore (as you have already noticed its major disadvantage: the compiler won't check the types of arguments for you). The argument type actually defaults to int in your example.
At the time, this syntax was used, one sometimes would find functions like
foo(p, q)
{
return q + p;
}
which was actually a valid definition, as the types for p, q, and the return type of foo default to int.
This is simply an old syntax, that pre-dates the "ANSI C" syntax you might be more familiar with. It's called "K&R C", typically.
Compilers support it to be complete, and to be able to handle old code bases, of course.
This is the original K&R syntax before C was standardized in 1989. C89 introduced function prototypes, borrowed from C++, and deprecated the K&R syntax. There is no reason to use it (and plenty of reasons not to) in new code.
That's a relic from when C had no prototypes for functions. Way back then, (I think) functions were assumed to return int and all its arguments were assumed to be int. There was no checking done on function parameters.
You're much better off using function prototypes in the current C language.
And you must use them in C99 (C89 still accepts the old syntax).
And C99 requires functions to be declared (possibly without a prototype). If you're writing a new function from scratch, you need to provide a declaration ... make it a prototype too: you lose nothing and gain extra checking from the compiler.
What is useful about this C syntax — using 'K&R' style function declarations?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
I was able to write this in Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
I don't understand. What's the point of this syntax? I can write:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
The only thing it seems to specify is how many parameters it uses and the return type. I guess parameters without types is kind of cool, but why allow it and the int paranName after the function declarator? It's weird.
Also is this still standard C?
The question you are asking is really two questions, not one. Most replies so far tried to cover the entire thing with a generic blanket "this is K&R style" answer, while in fact only a small part of it has anything to do with what is known as K&R style (unless you see the entire C language as "K&R-style" in one way or another :)
The first part is the strange syntax used in function definition
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
This one is actually a K&R-style function definition. Other answer have covered this pretty well. And there's not much to it, actually. The syntax is deprecated, but still fully supported even in C99 (except for "no implicit int" rule in C99, meaning that in C99 you can't omit the declaration of p2).
The second part has little to do with K&R-style. I refer to the fact that the function can be called with "swapped" arguments, i.e. no parameter type checking takes place in such a call. This has very little to do with K&R-style definition per se, but it has everything to do with your function having no prototype. You see, in C when you declare a function like this
int foo();
it actually declares a function foo that takes an unspecified number of parameters of unknown type. You can call it as
foo(2, 3);
and as
j = foo(p, -3, "hello world");
ans so on (you get the idea);
Only the call with proper arguments will "work" (meaning that the others produce undefined behavior), but it is entirely up to you to ensure its correctness. The compiler is not required to diagnose the incorrect ones even if it somehow magically knows the correct parameter types and their total number.
Actually, this behavior is a feature of C language. A dangerous one, but a feature nevertheless. It allows you to do something like this
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
i.e. mix different function types in a "polymorphic" array without any typecasts (variadic function types can't be used here though). Again, inherent dangers of this technique are quite obvious (I don't remember ever using it, but I can imagine where it can be useful), but that's C after all.
Finally, the bit that links the second part of the answer to the first. When you make a K&R-style function definition, it doesn't introduce a prototype for the function. As far as function type is concerned, your func definition declares func as
int func();
i.e. neither the types nor the total number of parameters are declared. In your original post you say "... it seems to specify is how many params it uses ...". Formally speaking, it doesn't! After your two-parameter K&R-style func definition you still can call func as
func(1, 2, 3, 4, "Hi!");
and there won't be any constraint violation in it. (Normally, a quality compiler will give you a warning).
Also, a sometimes overlooked fact is that
int f()
{
return 0;
}
is also a K&R-style function definition that does not introduce a prototype. To make it "modern" you'd have to put an explicit void in the parameter list
int f(void)
{
return 0;
}
Finally, contrary to a popular belief, both K&R-style function definitions and non-prototyped function declarations are fully supported in C99. The former has been deprecated since C89/90, if I remember correctly. C99 requires the function to be declared before the first use, but the declaration is not required to be a prototype. The confusion apparently stems from the popular terminological mix-up: many people call any function declaration "a prototype", while in fact "function declaration" is not the same thing as "prototype".
This is pretty old K&R C syntax (pre-dates ANSI/ISO C). Nowadays, you should not use it anymore (as you have already noticed its major disadvantage: the compiler won't check the types of arguments for you). The argument type actually defaults to int in your example.
At the time, this syntax was used, one sometimes would find functions like
foo(p, q)
{
return q + p;
}
which was actually a valid definition, as the types for p, q, and the return type of foo default to int.
This is simply an old syntax, that pre-dates the "ANSI C" syntax you might be more familiar with. It's called "K&R C", typically.
Compilers support it to be complete, and to be able to handle old code bases, of course.
This is the original K&R syntax before C was standardized in 1989. C89 introduced function prototypes, borrowed from C++, and deprecated the K&R syntax. There is no reason to use it (and plenty of reasons not to) in new code.
That's a relic from when C had no prototypes for functions. Way back then, (I think) functions were assumed to return int and all its arguments were assumed to be int. There was no checking done on function parameters.
You're much better off using function prototypes in the current C language.
And you must use them in C99 (C89 still accepts the old syntax).
And C99 requires functions to be declared (possibly without a prototype). If you're writing a new function from scratch, you need to provide a declaration ... make it a prototype too: you lose nothing and gain extra checking from the compiler.
What is useful about this C syntax — using 'K&R' style function declarations?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
I was able to write this in Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
I don't understand. What's the point of this syntax? I can write:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
The only thing it seems to specify is how many parameters it uses and the return type. I guess parameters without types is kind of cool, but why allow it and the int paranName after the function declarator? It's weird.
Also is this still standard C?
The question you are asking is really two questions, not one. Most replies so far tried to cover the entire thing with a generic blanket "this is K&R style" answer, while in fact only a small part of it has anything to do with what is known as K&R style (unless you see the entire C language as "K&R-style" in one way or another :)
The first part is the strange syntax used in function definition
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
This one is actually a K&R-style function definition. Other answer have covered this pretty well. And there's not much to it, actually. The syntax is deprecated, but still fully supported even in C99 (except for "no implicit int" rule in C99, meaning that in C99 you can't omit the declaration of p2).
The second part has little to do with K&R-style. I refer to the fact that the function can be called with "swapped" arguments, i.e. no parameter type checking takes place in such a call. This has very little to do with K&R-style definition per se, but it has everything to do with your function having no prototype. You see, in C when you declare a function like this
int foo();
it actually declares a function foo that takes an unspecified number of parameters of unknown type. You can call it as
foo(2, 3);
and as
j = foo(p, -3, "hello world");
ans so on (you get the idea);
Only the call with proper arguments will "work" (meaning that the others produce undefined behavior), but it is entirely up to you to ensure its correctness. The compiler is not required to diagnose the incorrect ones even if it somehow magically knows the correct parameter types and their total number.
Actually, this behavior is a feature of C language. A dangerous one, but a feature nevertheless. It allows you to do something like this
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
i.e. mix different function types in a "polymorphic" array without any typecasts (variadic function types can't be used here though). Again, inherent dangers of this technique are quite obvious (I don't remember ever using it, but I can imagine where it can be useful), but that's C after all.
Finally, the bit that links the second part of the answer to the first. When you make a K&R-style function definition, it doesn't introduce a prototype for the function. As far as function type is concerned, your func definition declares func as
int func();
i.e. neither the types nor the total number of parameters are declared. In your original post you say "... it seems to specify is how many params it uses ...". Formally speaking, it doesn't! After your two-parameter K&R-style func definition you still can call func as
func(1, 2, 3, 4, "Hi!");
and there won't be any constraint violation in it. (Normally, a quality compiler will give you a warning).
Also, a sometimes overlooked fact is that
int f()
{
return 0;
}
is also a K&R-style function definition that does not introduce a prototype. To make it "modern" you'd have to put an explicit void in the parameter list
int f(void)
{
return 0;
}
Finally, contrary to a popular belief, both K&R-style function definitions and non-prototyped function declarations are fully supported in C99. The former has been deprecated since C89/90, if I remember correctly. C99 requires the function to be declared before the first use, but the declaration is not required to be a prototype. The confusion apparently stems from the popular terminological mix-up: many people call any function declaration "a prototype", while in fact "function declaration" is not the same thing as "prototype".
This is pretty old K&R C syntax (pre-dates ANSI/ISO C). Nowadays, you should not use it anymore (as you have already noticed its major disadvantage: the compiler won't check the types of arguments for you). The argument type actually defaults to int in your example.
At the time, this syntax was used, one sometimes would find functions like
foo(p, q)
{
return q + p;
}
which was actually a valid definition, as the types for p, q, and the return type of foo default to int.
This is simply an old syntax, that pre-dates the "ANSI C" syntax you might be more familiar with. It's called "K&R C", typically.
Compilers support it to be complete, and to be able to handle old code bases, of course.
This is the original K&R syntax before C was standardized in 1989. C89 introduced function prototypes, borrowed from C++, and deprecated the K&R syntax. There is no reason to use it (and plenty of reasons not to) in new code.
That's a relic from when C had no prototypes for functions. Way back then, (I think) functions were assumed to return int and all its arguments were assumed to be int. There was no checking done on function parameters.
You're much better off using function prototypes in the current C language.
And you must use them in C99 (C89 still accepts the old syntax).
And C99 requires functions to be declared (possibly without a prototype). If you're writing a new function from scratch, you need to provide a declaration ... make it a prototype too: you lose nothing and gain extra checking from the compiler.