As every answer (so far) has said: to avoid the errors, declare the function before its use, and as Chris Jester-Young points out, use the standard mechanisms for accessing the variadic arguments or suffer the pains of Undefined Behavior.
In this example, it is not that the declaration before use in this case is required because of the function's return type, but rather because it does not match the default signature for an undeclared function: int u()
; that is, a function taking unspecified arguments returning an int
. Specifically, the actual definition int maw(int,int,...)
is inconsistent with different from the assumed declaration int maw()
which causes GCC to say "conflicting types for ‘maw’".
Your second example
int main() {
abc(); ..... return 0;
}
abc() { ....... }
works because the later definition of abc
doesn't contradict the default signature assumed when its first call was encountered. But just because it works doesn't make it good form because you get almost no type safety from the default signature.
Access to the variadic arguments (the ones matching the ...
) really should be done through the standard mechanisms of stdarg.h
, unless you are implementing a compiler and are the author of that compiler's stdarg.h
. For instance, on some architectures those arguments may not even be passed on the stack, but they can still be located by the macros from stdarg.h
.
Edit: I reworded the second paragraph to say what I meant in a different, and I hope clearer, way.
The compiler needs to know that the function is variadic before the first call because on some architectures, it might be required to pass the variadic parameters differently than normal parameters. That is especially true of certain register-window RISK architectures, and those that might pass the first 2 ints and first 2 floats in registers, but must put all variadics on the stack even if there is room in the regsisters.
A similar declare before use situation exists for functions that do not use the cdecl
calling convention. You will usually run into this when linking modules written in Pascal or FORTRAN with modules written in C. However, many of the Windows API functions exported by the core DLLs assume a calling convention named stdcall
and if the compiler were to use a cdecl
style call, the program would crash (and the whole machine on Windows 9x or earlier).