20

I understand that if a source file need to reference functions from other file then it needs to include its header file, but I don't understand why the source file include its own header file. Content in header file is simply being copied and pasted into the source file as function declarations in per-processing time. For source file who include its own header file, such "declaration" doesn't seem necessary to me, in fact, project still compile and link no problem after remove the header from it's source file, so what's the reason for source file include its own header?

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Chen
  • 326
  • 3
  • 12
  • Did you try doing it without including it? Which error messages did you get? – πάντα ῥεῖ Jun 13 '15 at 10:26
  • 9
    Not giving the C compiler an opportunity to tell you that there is a mismatch between the declaration and the implementation of the function is a mistake. Without that help you'll lose several of hours of your life discovering such a mismatch. It happens at the worst possible time, a year from now when you don't remember the code all that well and you make a seemingly innocent change. Making your program blow up in a very hard to diagnose way. It does have to be learned the hard way. – Hans Passant Jun 13 '15 at 10:41

5 Answers5

26

The main benefit is having the compiler verify consistency of your header and its implementation. You do it because it is convenient, not because it is required. It may definitely be possible to get the project to compile and run correctly without such inclusion, but it complicates maintenance of your project in the long run.

If your file does not include its own header, you can accidentally get in a situation when forward declaration of a function does not match the definition of the function - perhaps because you added or removed a parameter, and forgot to update the header. When this happens, the code relying on the function with mismatch would still compile, but the call would result in undefined behavior. It is much better to have the compiler catch this error, which happens automatically when your source file includes its own header.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    Can you tell me how the compiler verify the consistency? it's magical to me in the compile time how the compiler can tell if the included header file is it's own or others? – Chen Jun 13 '15 at 10:51
  • @Chen The relationship between the header and the `.c` file is that the header includes declarations for the functions and global variables that the `.c` file defines. E.g. for functions the header contains prototypes, the `.c` file contains a full definition; the compiler checks that the full definition has the same argument and return types as the prototype which it saw earlier when compiling the included header. – Gilles 'SO- stop being evil' Jun 13 '15 at 10:54
  • 3
    @Chen The compiler has no idea the header is related to a source file in any way. All it cares about is that the function prototypes from the header matched function definitions from the source file. When there is a mismatch, an error is triggered. – Sergey Kalinichenko Jun 13 '15 at 11:00
  • @dasblinkenlight that's exactly the point I don't understand: if the included header file in source file is others, which's function prototypes are totally "mismatch", why no error triggered then. – Chen Jun 13 '15 at 11:09
  • 3
    @Chen When you include a header from some other source file, the compiler has access only to the prototype. As long as actual parameters match the prototype, the compiler will not complain, even if the implementation is different. The compiler has no way to check the implementation, because it is in another file. When you include the header from a file that has implementations of the functions, the compiler has access to both the prototype and the implementation, so it can check one against the other. If the prototype does not match the actual definition, the compiler will complain. – Sergey Kalinichenko Jun 13 '15 at 11:22
  • @dasblinkenlight I assume what you mean "mismatch" is function return type and parameters. If I use C compiler, which has no name mangling for functions, the only "mismatch" between prototype and the implementation is the function name. does it means the error check won't work in this case? – Chen Jun 13 '15 at 12:00
  • 1
    @Chen A mismatch between a prototype and its implementation would be when the function name is the same, but return type and/or formal parameter types are different. Name mangling could have prevented errors in situations like this, because the linker would detect a missing function, but as you correctly noted in your comment, C does not have name mangling. – Sergey Kalinichenko Jun 13 '15 at 12:06
  • @dasblinkenlight thank you, that's all I need to know, so basically, to take the advantage of this error check mechanism, the C source files need to be compiled with a C++ compiler. – Chen Jun 13 '15 at 12:21
  • @Chen There is perfectly valid C code that cannot be compiled with C++ compiler (e.g. assignment of `malloc` result is allowed in C without a cast, but C++ requires a cast). In addition, certain constructs have semantic that differs in subtle yet important ways. But if your source is such that it can be compiled with C++ compiler, you could certainly take advantage of name mangling offered by C++. – Sergey Kalinichenko Jun 13 '15 at 12:31
7

Practical example - assume the following files in a project:

/* foo.h */
#ifndef FOO_H
#define FOO_H
double foo( int x );
#endif

/* foo.c */
int foo( int x )
{
  ...
}

/* main.c */
#include "foo.h"

int main( void )
{
  double x = foo( 1 );
  ...
}

Note that the declaration infoo.h does not match the definition in foo.c; the return types are different. main.c calls the foo function assuming it returns a double, according to the declaration in foo.h.

foo.c and main.c are compiled separately from each other. Since main.c calls foo as declared in foo.h, it compiles successfully. Since foo.c does not include foo.h, the compiler is not aware of the type mismatch between the declaration and definition, so it compiles successfully as well.

When you link the two object files together, the machine code for the function call won't match up with what the machine code for function definition expects. The function call expects a double value to be returned, but the function definition returns an int. This is a problem, especially if the two types aren't the same size. Best case scenario is you get a garbage result.

By including foo.h in foo.c, the compiler can catch this mismatch before you run your program.

And, as is pointed out in an earlier answer, if foo.h defines any types or constants used by foo.c, then you definitely need to include it.

John Bode
  • 119,563
  • 19
  • 122
  • 198
5

The header file tells people what the source file can do.

So the source file for the header file needs to know its obligations. That is why it is included.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
4

Yours seems a borderline case, but an include file can be viewed as a sort of contract between that source file and any other source files that may require those functions.

By writing the "contract" in a header file, you can ensure that the other source files will know how to invoke those functions, or, rather, you will be sure that the compiler will insert the correct code and check its validity at compile time.

But what if you then (even inadvertently) changed the function prototype in the corresponding source file?

By including in that file the same header as everyone else, you will be warned at compile time should a change inadvertently "break" the contract.

Update (from @tmlen's comment): even if in this case it does not, an include file may also use declarations and pragmas such as #defines, typedef, enum, struct and inline as well as compiler macros, that would make no sense writing more than once (actually that would be dangerous to write in two different places, lest the copies get out of sync with each other with disastrous results). Some of those (e.g. a structure padding pragma) could become bugs difficult to track down.

LSerni
  • 55,617
  • 10
  • 65
  • 107
  • 3
    Also the header may include `typedef`s, `struct`s, `enum`s, `inline` functions, macros, etc. that both the source and others that use the library use. – tmlen Jun 13 '15 at 10:30
  • Very good point. I have included it in my own answer, unless you prefer to supply one of your own...? – LSerni Jun 13 '15 at 10:35
1

It is useful because functions can be declared before they are defined.

So it happens that you have the declaration, followed by a call\invocation, followed by the implementation. You don't have to, but you can.

The header file contains the declarations. You're free to invoke anytime as long as the prototype matches. And as long as the compiler finds an implementation before finishing compilation.

Ely
  • 10,860
  • 4
  • 43
  • 64