C language is now a rather old language. In the first versions (known as K&R C or pre-ansi C from the 70's) functions prototypes did not exists, and the declaration of a function only declared the return type. As the default return type was int
some programmers (many?) used not to declare functions returning int
values. And this legacy behaviour is still observed by current compilers: if the compiler sees a function usage with no previous declaration, it assumes that it is a function returning int
and taking an arbitrary number of parameters.
So the compiler is right when it compiles your code with no errors.
That being said, calling a function whose definition expects a precise number of parameters with a different number of parameter or with wrong parameter types invokes Undefined Behaviour. That means that per standard no requirement exists on how the program will behave at run time. Said differently never do that in a real world program.
For the actual results, many compilers use the so-called C calling convention: the parameters are put in the stack in reverse order by the caller, the callee uses them using the current position of the stack pointer, and in the end, the stack is cleared by the caller. This is the reason why passing more parameters than expected is thinked to be harmless. Anyway it still explicitely invokes UB, so a different compilation (different compiler or compilation options) could lead to a very different behaviour. And it also explains why passing less parameters than expected just let initialized values (the current content of the stack) for the missing parameters.
But what you should remember is only that passing a wrong number of parameters or using wrong parameter types is explicitely Undefined Behaviour, even if the absence of a definition can prevent the compiler to raise an error.