Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should I include an header file? And how #include actually works? [closed]

Tags:

c

header-files

At first, I was writing my function in an .h file and then include it with #include "myheader.h". Then, someone said me that it's better to add to these files only functions prototypes and to put the real code in a separate .c file. Now, I'm able to compile more .c files to generate only an executable, but at this point I can't understand why I should add the header files if the code is in another file.

Moreover, I had a look to standard C libraries (like stdlib.h) in the system and it seemed to me to store only structure definitions, constants and similar... I'm not so good with C (and to be honest, stdlib.h was almost Chinese to me, no offense for Chinese of course :) ), but I didn't spot any single line of 'operative' code. However, I always just include it without adding anything else and I compile my files as if the 'code' was actually there.

Can someone please explain me how do these things work? Or, at least, point me to a good guide? I searched on Google and SO, also, but didn't find anything that explains it clearly.

like image 220
Zagorax Avatar asked Nov 30 '22 05:11

Zagorax


2 Answers

When you compile C code, the compiler has to actually know that a particular function exists with a defined name, parameter list, return type and optional modifiers. All these things are called function signature and the existence of a particular function is declared in the header file. Having this information, when the compiler finds a call to this function, it will know which type of parameters to look for, can control whether they have the appropriate type and prepare them to a structure that will be pushed to the stack before the code actually jumps to your function implementation. However the compiler does not have to know the actual implementation of the function, it simple puts a "placeholder" in your object file to all function calls. (Note: each c files compiles to exactly one object file). #include simple takes the header file and replaces the #include line with the contents of the file.

After the compilation the build script passes all object files to the linker. The linker will be that resolves all function "placeholders" finding the physical location of the function implementation, let them be among your object files, framework libraries or dlls. It simple places the information where the function implementation can be found to all function calls thus your program will know where to continue execution when it arrives to your function call.

Having said all this it should be clear why you can't put function definition in the header files. If later you would #include this header in to more then one c file, both of them would compile the function implementation into two separate object files. The compiler would work well, but when the linker wanted to link together everything, it would find two implementation of the function and would give you an error.

stdlib.h and friends work the same way. The implementation of the functions declared in them can be found in framework libraries which the compiler links to your code "automatically" even if you are not aware of it.

like image 192
MrTJ Avatar answered Dec 18 '22 07:12

MrTJ


The C language (together with C++) uses a quite obsolete strategy for making the compiler know the functions defined elsewhere.

This strategy goes like this: the signatures of the functions etc. (this stuff is called declarations in C) go into a special file called header, and every other file which wants to use them is expected to almost literally include that header into the file (actually, #include directive just tells the compiler to include the literal text of the header), so that the compiler sees again the function declarations.

Other languages solve this problem in a different way: compiler sees all the source code, and remembers the metadata of the already compiled classes itself.

The strategy used in C shifts the task of finding all the dependencies from the compiler to the developer; it's a legacy from the old times when the computers were small, silly and slow, so this kind of help from the developer was really valuable.

Although this strategy has numerous drawbacks, and besides it's theoretically possible to change it now, the standard is not going to change, because gigabytes of code have been written in that style already.

tl;dr: it's a legacy from the 70's.

like image 32
Vlad Avatar answered Dec 18 '22 08:12

Vlad