Here’s a question that’s pretty special and one I’ve never been aware of before. Apparently I can create a function in C that differs from its function prototype in the passing parameters. The only requirement is that the function must not know the function prototype at compile time.
In my minimal example, I created the following header Test.h:
int Test(int);
I also created the following main.c:
#include <stdio.h>
#include "Test.h"
int main()
{
int a = Test(5);
int b = Test(5);
printf("%d", a);
}
When I use this Test.c, an error occurs when compiling, as expected:
#include <stdio.h>
#include "Test.h"
void Test(void)
{
printf("HW\n");
}
If I write Test.c like this, the program is compiled, linked and is executable. Of course, the variable a has a seemingly arbitrary value.
#include <stdio.h>
void Test(void)
{
printf("HW\n");
}
Why can this program be linked and where does the return parameter come from, for example?
This also seems very dangerous if something like this happens accidentally in larger code.
Quick additional info, when I use the same code in a C++ project, there are Linker Errors. So if I use main.cpp and Test.cpp instead of main.c and Test.c. Here things seem to be handled differently with the left. But I would also have been surprised, since C++ has function overloading.
>Solution :
The behavior is undefined, as you have observed.
The reason you do not get an error is the linker has no information about the calling convention used in Test.c and main.c the only information is the symbol name Test and the type of reference (function call).
Here is a possible sequence of events:
- The
mainfunction calls theTestfunction, which probably behaves as expected: it callsprintfwhich should printHWand a newline, then it returns without a return value. mainthen retrieves the return value it expects to have been stored in the conventional place where it should have been put byTest, in general, for anintreturn type, this is a register, andmaincallsprintf
to print this value.- There is a good chance the value printed is
3becauseprintfreturned3as anint, thus it stored 3 in the proper register, andTestprobably did not change the register between theprintfcall and its own return statement (no guarantee of that).
You can investigate more by making the compiler produce the assembly source code with -s or -S, or play with Godbolt Compiler Explorer
Compiling the code as C++ does produce an error because unlike C, C++ stores the argument types along with the function names (it constructs synthetic names in a process called mangling) so when you link the main.o object file with the incorrect Test.o, the function names do not match and you get a missing symbol error.