I'd like information on the behavior of pre-standard "K&R-style" function declaration syntax when used in conjunction with explicit function protoypes as introduced by ANSI. Specifically, the syntax that looks like this:
int foo(a)
int a;
{
/* ... */
}
as opposed to like this:
int foo(int a) {
/* ... */
}
Note that I am referring specifically to the function declaration syntax, not the usage of unprototyped functions.
Much has been made of how the former syntax does not create a function prototype. My research indicates that, if the function were defined as above, a subsequent call foo(8, 6, 7, 5, 3, 0, 9)
would result in undefined behavior; whereas with the latter syntax, foo(8, 6, 7, 5, 3, 0, 9)
would actually be invalid. This makes sense, but I explicitly forward-declare all my functions in the first place. If the compiler ever had to rely on a prototype generated from the definition, I'd already consider that a flaw in my code; so I make sure to use compiler warnings that notify me if I ever fail to forward-declare a function.
Assuming that proper forward-declarations are in place (in this case, int foo(int);
), is the K&R function declaration syntax still unsafe? If so, how? Does the usage of the new syntax negate the prototype that's already there? At least one person has apparently claimed that forward-declaring functions before defining them in the K&R style is actually illegal, but I've done it and it compiles and runs just fine.
Consider the following code:
/* 1 */ #include <stdio.h>
/* 2 */ void f(int); /*** <- PROTOTYPE IS RIGHT HERE ****/
/* 3 */ void f(a)
/* 4 */ int a;
/* 5 */ {
/* 6 */ printf("YOUR LUCKY NUMBER IS %d\n", a);
/* 7 */ }
/* 8 */
/* 9 */ int main(argc, argv)
/* 10 */ int argc;
/* 11 */ char **argv;
/* 12 */ {
/* 13 */ f(1);
/* 14 */ return 0;
/* 15 */ }
When given this code verbatim, gcc -Wall
and clang -Weverything
both issue no warning and produce programs that, when run, print YOUR LUCKY NUMBER IS 1
followed by a newline.
If f(1)
in main()
is replaced with f(1, 2)
, gcc
issues a "too many arguments" error on that line, with the "declared here" note notably indicating line 3, not line 2. In clang
, this is a warning, not an error, and no note indicating a declaration line is included.
If f(1)
in main()
is replaced with f("hello world")
, gcc
issues an integer conversion warning on that line, with a note indicating line 3 and reading "expected 'int' but argument is of type 'char *'". clang
gives a similar error, sans note.
If f(1)
in main()
is replaced with f("hello", "world")
, the above results are both given, in sequence.
My question is this: assuming function prototypes are already provided, is the K&R syntax any less safe than the style with inline type keywords? The answer indicated by my research is, "Nope, not a bit", but the overwhelmingly negative, apparently near-unanimous opinion of the older style of type declaration makes me wonder if there isn't something I'm overlooking. Is there anything I'm overlooking?