The order in which I group my header includes is as follows. Each section is separated by exactly one blank line, even if the section only has one include.
""
Internal headers""
Internal generated headers (e.g. fromversion.h.in
; okay to use from include path)""
Internal third-party headers (vendored into project)""
Private API headers (always relative paths)""
Public API headers<>
Build-system level third party headers (e.g. from CMake'sadd_subdirectory()
; always from include path)<>
System-wide third party (but not platform) headers (e.g. fromsudo apt install ...
)<>
Platform headers (e.g.unistd.h
,sys/net.h
, etc.)<>
Standard library headers
Any conditionally included headers come as early as technically possible (barring inclusion-order constraints), but not earlier than their respective section (corollary: conditional includes in section X should be preceded by all unconditional includes also in section X).
Here are a few real-world examples (with added comments showing which section they belong to):
/* from Minimap, src/context.c */
//-> 1. internal
#include "./context.h"
#include "./init.h"
#include "./string.h"
#include "./error.h"
//-> 3. internal third-party
#include "./third_party/cwalk.h"
//-> 4. public API
#include "../include/minimap.h"
//-> 6. system-wide third-party
#include <git2.h>
//-> 7. platform
#include <unistd.h>
//-> 8. standard
#include <assert.h>
#include <string.h>
#include <limits.h>
/* from Minimap, src/init.c */
//-> 1. internal
#include "./init.h"
#include "./error.h"
//-> 2. internal generated (seen here using internal include path)
#include "minimap--generated-version-info.h" /* see CMakeLists.txt */
//-> 4. public API
#include "../include/minimap.h"
//-> 6. system-wide third-party
#include <git2.h>
//-> 8. standard
#include <assert.h>
// from Tide Online; note that the <tide/*> includes
// are from intra-project modules linked together
// as though they were individual modules *all done
// via CMake targets* so this was the rationale behind
// including them with <> as opposed to "" (they functioned
// more like third-party modules than internal modules).
//-> 1. internal
#include "./render/thread.hh"
#include "./game/thread.hh"
#include "./physics/thread.hh"
#include "./fatal-error.hh"
//-> 5. build-system third-party (see above comment)
#include <tide/log.hh>
#include <tide/util.hh>
#include <tide/engine.hh>
#include <tide/assert.hh>
//-> 8. standard
#include <csignal>
#include <stdexcept>
#include <cstdlib>
#include <chrono>
#include <thread>
#include <string>
/*
From the ORO operating system stage 0 loader's
x86 CPU VGA driver.
Note that the FRAMAC include was
required first due to technical reasons,
which of course outweighs any subjective
ordering conventions.
*/
#ifdef __FRAMAC__
# include <string.h>
#endif
//-> 1. internal
#include "./vga.h"
#include "../boot.h"
//-> 4. private API
#include "../../stage1/string.h"
#include "../../stage1/types.h"