Is using headers multiple times bad?

Lets say I am using header guards,

#ifndef MAIN_H
#define MAIN_H

#include "foo.h"
#include "some_header_file.h"

... // Some Code

#endif   

Inside foo.h file also with Header guards.

#ifndef FOO_H
#define FOO_H

#include "some_header_file.h"
... // Some Code

#endif   

As you can see main file have 2 headers one of them is dublicate. I have three questions:

  1. Does Header guards prevent duplicate header files?
  2. Does the compiler optimize it and removes it?
  3. Is this a bad practice and the extra header file should be deleted from main file?

Solution 1:

Does Header guards prevent duplicate header files?

Yes. The first encountered inclusion will bring the content of the header to the translation unit, and the header guard causes successive inclusions to be empty which prevents the content of the header from being duplicated. This is exactly the reason why header guards are used.

or is this a bad practice and the extra header file should be deleted from main file?

No, the duplicate inclusion is not a bad practice. If the "main" header depends on any declaration from "some_header_file.h", then "main" absolutely should include "some_header_file.h" directly, whether another header - even one included by "main" - also includes it or not.

Relying on a transitive inclusion would generally be a bad practice - i.e. in this case it may be bad to rely on the detail that "foo.h" includes "some_header_file.h" when including "foo.h" into "main". Such assumptions often can cause programs to break unexpectedly when they are modified. In this case, if "foo.h" was modified to no longer depend on "some_header_file.h", and that inclusion was removed, then that change would suddenly cause the assumption to fail, and "some_header_file.h" would no longer be included into "main" as a result of change that didn't involve "main" at all. That would be bad.

Solution 2:

The main problem with repited includes is when two different files include each other. For example, if a.h include b.h, and b.h includes a.h, if you don't add header guards, preprocessor ends up in a cycle, because every time it reads a.h includes b.h, and b.h includes a.h, and this never ends.

In your case you could have some problem if you define a variable in your some_header_file.h", because it would be read twice and the variables would be declared twice also, which would result in a compiler error.

You need to add them in "some_header_file.h", that way next time preprocessor reads this file it would ignore it by the ifndef clause. And notice the importance for cyclic include dependencies.

In "some_header_file.h" add:

#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
...code
#endif /* SOME_HEADER_FILE_H */

Last comment isn't necessary, but it helps case you need to debug/review preprocessors output.