148

When coding in either C or C++, where should I have the #include's?

callback.h:

#ifndef _CALLBACK_H_
#define _CALLBACK_H_

#include <sndfile.h>
#include "main.h"

void on_button_apply_clicked(GtkButton* button, struct user_data_s* data);
void on_button_cancel_clicked(GtkButton* button, struct user_data_s* data);

#endif

callback.c:

#include <stdlib.h>
#include <math.h>

#include "config.h"

#include "callback.h"
#include "play.h"

void on_button_apply_clicked(GtkButton* button, struct user_data_s* data) {
  gint page;
  page = gtk_notebook_get_current_page(GTK_NOTEBOOK(data->notebook));

  ...

Should all includes be in either the .h or .c / .cpp, or both like I have done here?

Louise
  • 6,193
  • 13
  • 36
  • 36
  • 2
    Let me turn this around and ask: what was _your_ criteria for deciding to put sndfile.h and main.h in callback.h? – Owen S. Jun 08 '10 at 23:38
  • 1
    for anyone else interested in more details there's [this](https://softwareengineering.stackexchange.com/a/331662). – Diego Rodriguez Mar 29 '21 at 21:04

5 Answers5

202

Put as much as you can in the .c and as little as possible in the .h. The includes in the .c are only included when that one file is compiled, but the includes for the .h have to be included by every file that uses it.

Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • 8
    True, but doesn't the `#ifndef _CALLBACK_H_`, on the top of it, prevent the compiler in processing it more than once? – hytromo Feb 08 '14 at 12:25
  • 17
    @user9379 That will prevent it from being included more than once per .c or .cpp file. Each .c or .cpp file is generally build individually though, which means a .h will be re-parsed for each .c or .cpp file you compile. – Brendan Long Feb 09 '14 at 00:29
  • 4
    I think that the main reason to put as little as possible in the `.h` is to avoid in some cases an error because of a loop of inclusion. Example: two classes need one another for their implementations, but not for their declarations. Putting both includes in the `.cpp`s will avoid an error. – Codoscope Jan 09 '17 at 20:09
  • 2
    @Qu'est-cet'yont That's a reason why you *can't* put certain things in the .h files. This answer is about why you should put even less than that. – Brendan Long Jan 09 '17 at 20:50
  • @BrendanLong I see, although in my sense including several times a same header doesn't matter if you put the correct macros inside to include the content only once. Therefore, I think that putting even less is to reduce probabilities to get an error in the future with modifications of the code. – Codoscope Jan 09 '17 at 22:21
  • In a big project there may be an increase in build times with repetition of includes into .c/.cpp, but by what? More time than it takes to sip coffee? And irrelevant with respect to program load times where the .exe will not suffer either way. – ste3e Oct 04 '22 at 02:02
67

The only time you should include a header within another .h file is if you need to access a type definition in that header; for example:

#ifndef MY_HEADER_H
#define MY_HEADER_H

#include <stdio.h>

void doStuffWith(FILE *f); // need the definition of FILE from stdio.h

#endif

If header A depends on header B such as the example above, then header A should include header B directly. Do NOT try to order your includes in the .c file to satisfy dependencies (that is, including header B before header A); that is a big ol' pile of heartburn waiting to happen. I mean it. I've been in that movie several times, and it always ended with Tokyo in flames.

Yes, this can result in files being included multiple times, but if they have proper include guards set up to protect against multiple declaration/definition errors, then a few extra seconds of build time isn't worth worrying about. Trying to manage dependencies manually is a pain in the ass.

Of course, you shouldn't be including files where you don't need to.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 1
    Why not just forward declare File `class File;` and include stdio in .cpp where doStuffWith define? – Oleksa Sep 03 '20 at 17:27
  • 2
    @olekstolar: In this particular case that won't work because `FILE` is a typedef name, not a class name. We need that `typedef xxx FILE;` definition from `stdio.h`. In other cases yes, you can forward declare incomplete types like `struct foo;` or `class bar;` and not include the header file, but now you've increased your maintenance burden. You have to keep your forward declarations in sync with what's in the header file - it's just easier to include the header file. No, the types in `stdio.h` are not likely to change, but in user-defined headers they can change a lot. – John Bode Sep 03 '20 at 18:38
19

Put as many includes in your cpp as possible and only the ones that are needed by the hpp file in the hpp. I believe this will help to speed up compilation, as hpp files will be cross-referenced less.

Also consider using forward declarations in your hpp file to further reduce the include dependency chain.

Parappa
  • 7,566
  • 3
  • 34
  • 38
  • 1
    Oo. The forward declarations thing is interesting. – Brendan Long Jun 09 '10 at 00:18
  • 1
    Parappa, forward declarations are very useful in circular reference scenarios. But would they be a good practice in other scenarios? (I new in C++, so I am honestly asking) – Dzyann Nov 20 '13 at 20:25
6

If I #include <callback.h>, I don't want to have to #include lots of other header files to get my code to compile. In callback.h you should include everything needed to compile against it. But nothing more.

Consider whether using forward declarations in your header file (such as class GtkButton;) will suffice, allowing you to reduce the number of #include directives in the header (and, in turn, my compilation time and complexity).

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
  • I disagree. Including the whole world in H files increases the dependancy chain and therefore compile times. – John Dibling Jun 09 '10 at 00:03
  • 1
    My answer didn't recommend including the whole world in the header file, I suggested including *just* enough so that the user of the API doesn't have to spend time searching for dependencies. – johnsyweb Jun 09 '10 at 00:21
0

I propose to simply include an All.h in the project that includes all the headers needed, and every other .h file calls All.h and every .c/.cpp file only includes its own header.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
ste3e
  • 995
  • 1
  • 9
  • 18