The query you might be asking is admittedly two questions, not one. Most replies to this point have tried to cowl the whole factor with a generic blanket “that is Ok&R type” reply, whereas, in reality, solely a small a part of it has something to do with what is called Ok&R type (except you see the whole C language as “Ok&R-style” in a method or one other 🙂
The primary half is the unusual syntax used within the perform definition
int func(p, p2)
void *p;
int p2; /* <- non-obligatory in C89/90, however not in C99 */
{
return 0;
}
This one is definitely a Ok&R-style perform definition. Different solutions have lined this gorgeous properly. And there is not a lot to it, truly. The syntax is deprecated however nonetheless absolutely supported even in C18 (aside from “no implicit int” rule in C99 or later, that means that in C99 you may’t omit the declaration of p2
).
The second half has little to do with Ok&R-style. I discuss with the truth that the perform will be referred to as with “swapped” arguments, i.e. no parameter kind checking takes place in such a name. This has little or no to do with Ok&R-style definition per se, but it surely has every little thing to do together with your perform having no prototype. You see, in C, if you declare a perform like this
int foo();
it truly declares a perform foo
that takes an unspecified variety of parameters of unknown kind. You’ll be able to name it as
foo(2, 3);
and as
j = foo(p, -3, "hiya world");
and so forth (you get the concept);
Solely the decision with correct arguments will “work” (that means that the others produce undefined conduct), however it’s totally as much as you to make sure its correctness. The compiler isn’t required to diagnose the wrong ones, even when it in some way magically is aware of the right parameter sorts and their complete quantity.
Truly, this conduct is a characteristic of C language. A harmful one, however a characteristic nonetheless. It means that you can do one thing like this:
void foo(int i);
void bar(char *a, double b);
void baz(void);
int foremost()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
i.e. combine completely different perform sorts in a “polymorphic” array with none typecasts (variadic perform sorts cannot be used right here, although). Once more, the inherent risks of this system are fairly apparent (I do not keep in mind ever utilizing it, however I can think about the place it may be helpful), however that is C in any case.
Lastly, the bit that hyperlinks the second a part of the reply to the primary. Whenever you make a Ok&R-style perform definition, it does not introduce a prototype for the perform. So far as perform kind is worried, your func
definition declares func
as
int func();
i.e. neither the categories nor the whole variety of parameters are declared. In your unique submit, you say, “… it appears to specify is what number of params it makes use of …”. Formally talking, it does not! After your two-parameter Ok&R-style func
definition, you continue to can name func
as
func(1, 2, 3, 4, "Hello!");
and there will not be any constraint violation in it. (Usually, a high quality compiler gives you a warning).
Additionally, a generally neglected reality is that
int f()
{
return 0;
}
can be a Ok&R-style perform definition that doesn’t introduce a prototype. To make it “trendy” you’d must put an express void
within the parameter checklist:
int f(void)
{
return 0;
}
Lastly, opposite to standard perception, each Ok&R-style perform definitions and non-prototyped perform declarations are absolutely supported in C99 and past (as much as C18, however not in C23). The previous has been deprecated since C89/90, if I keep in mind accurately. C99 requires the perform to be declared earlier than the primary use, however the declaration isn’t required to be a prototype. The confusion apparently stems from the favored terminological mix-up: many individuals name any perform declaration “a prototype”, whereas, in reality, “perform declaration” isn’t the identical factor as “prototype”.
Be aware that C23 will change the principles. The Ok&R type perform definition will now not be commonplace C. Additional, a perform declaration reminiscent of extern int func();
will declare a perform prototype equal to extern int func(void);
— simply as in C++. And a perform definition reminiscent of int func() { … }
will outline a prototype for the perform.