There is no magic. When C is compiled, there are two important steps for it.
First, each individual compilation unit is compiled into isolation. (A compiler is basically one .c file, plus everything that it includes).
At this stage, he does not know anything about what is contained in other .c files, which means that he cannot create a complete program. It can generate code with a few spots to fill in the blanks. If from foo.c you call a function declared in bar.h and defined in bar.c, then the compiler can only see that the function exists. It is declared in bar.h, so we must assume that a complete definition exists. But since this definition is inside another compilation module, we cannot yet see it. Thus, the compiler generates code to call the function, with a small note on it saying: "Fill in the address of this function when it is really known."
Once each compilation unit has been compiled in this way, you are left with a bunch of object files (usually .o if they are compiled by GCC and .obj if you use MSVC) containing this kind of "filling in the blanks". "
Now the linker takes all these object files and tries to combine them together, which allows you to fill in the gaps. Now we can find the function that we created for the call, so we can insert its address into the call.
Therefore, nothing special happens if the .c file has the same name as .h. This is just a convention that makes it easier for people to understand what is inside each file.
The compiler doesn't care. It simply takes each .c file, plus everything it includes, and compiles it into an object file. And then the linker combines all these object files together into one executable file.
source share