The C programming language is essentially a single-scan language – a compiler doesn’t need to reread the code but it can assemble it line by line, retaining information only on how identifiers were declared.
The C89 standard had the concept of implicit declaration. In absence of a declaration, the function p1
is declared implicitly as int p1()
; i.e. a function that returns an int
and takes unspecified arguments that go through default argument promotions. When you call such a function giving it a float
as an argument, the float argument is promoted to a double
, as called for by default argument promotions. It would be fine if the function was int p1(double arg)
; but the expected argument type is unsigned int
, and the return value is not compatible either (void
vs int
). This mismatch will cause the program to have undefined behaviour – there is no point in reasoning what is happening then. However, there are many old C programs that would fail to compile, if the compilers wouldn’t support the archaic implicit declarations – thus you just need to consider all these warnings as errors.
Notice that if you change the return value of p1
into an int
, you will get less warnings:
% gcc implicit.c
implicit.c:14:5: warning: implicit declaration of function ‘p1’ [-Wimplicit-function-declaration]
p1(fvar);
^~
But the observed behaviour on my compiler would be mostly the same.
Thus the presence of mere warning: implicit declaration of function ‘x’ is quite likely a serious error in newly written code.
Were the function declared before its use, as is case with p2
, then the compiler knows that it expects an unsigned long
as the argument, and returns void
, and therefore it would know to generate correct conversion code from float
to unsigned long
for the argument.
The C99 and C11 do not allow implicit function declarations in strictly-conforming programs – but they also do not require a conforming compiler to reject them either. C11 says:
An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
and a footnote noting that
Thus, an undeclared identifier is a violation of the syntax.
However, it doesn’t require a compiler to reject them.
3
solved Passing float to a function with int argument (that is not declared beforehand)