c++ - otro - incluir header en c
C/C++ incluye orden de archivo de cabecera (10)
¿Qué orden debe incluir los archivos especificados, es decir, cuáles son las razones para incluir un encabezado antes de otro?
Por ejemplo, ¿los archivos del sistema, STL y Boost van antes o después de los archivos de inclusión locales?
Es una pregunta difícil en el mundo C / C ++, con tantos elementos más allá del estándar.
Creo que el orden de los archivos de cabecera no es un problema grave mientras se compile, como dijo squelart.
Mis ideas son: Si no hay conflicto de símbolos en todos esos encabezados, cualquier orden es correcta, y el problema de la dependencia del encabezado se puede solucionar más adelante agregando #incluir líneas a la .h defectuosa.
La verdadera molestia surge cuando un encabezado cambia su acción (al verificar las condiciones de #if) de acuerdo con lo que se encuentra arriba.
Por ejemplo, en stddef.h en VS2005, hay:
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
Ahora el problema: si tengo un encabezado personalizado ("custom.h") que se debe usar con muchos compiladores, incluidos algunos más antiguos que no proporcionan offsetof
en sus encabezados de sistema, debería escribir en mi encabezado:
#ifndef offsetof
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
Y asegúrese de decirle al usuario #include "custom.h"
después de todos los encabezados del sistema, de lo contrario, la línea de offsetof
en stddef.h afirmará un error de redefinición de macros.
Oramos para no encontrarnos más de estos casos en nuestra carrera.
Esto no es subjetivo. Asegúrese de que sus encabezados no se basen en #include
d en un orden específico. Puede estar seguro de que no importa en qué orden incluya los encabezados STL o Boost.
Estoy bastante seguro de que esta no es una práctica recomendada en ningún lugar del mundo sano, pero me gusta alinear los sistemas con la longitud del nombre del archivo, ordenados léxicamente dentro de la misma longitud. Al igual que:
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
Creo que es una buena idea incluir sus propios encabezados antes que otros pueblos, para evitar la vergüenza de la dependencia del orden de inclusión.
Incluya desde el más específico hasta el menos específico, comenzando con el .hpp correspondiente para el .cpp, si existe uno. De esa manera, se revelarán las dependencias ocultas en los archivos de encabezado que no sean autosuficientes.
Esto se complica por el uso de encabezados precompilados. Una forma de evitar esto es, sin hacer que el compilador de su proyecto sea específico, es utilizar uno de los encabezados del proyecto como el archivo de inclusión del encabezado precompilado.
Lo importante a tener en cuenta es que sus encabezados no deben depender de que otros encabezados se incluyan primero. Una forma de asegurar esto es incluir sus encabezados antes que cualquier otro encabezado.
"Thinking in C ++" en particular menciona esto, haciendo referencia al "Diseño de software a gran escala C ++ de Lakos":
Los errores de uso latentes pueden evitarse asegurándose de que el archivo .h de un componente se analice por sí mismo, sin declaraciones ni definiciones proporcionadas externamente ... Incluyendo el archivo .h como la primera línea del archivo .c, se garantiza que no haya piezas críticas. La información intrínseca a la interfaz física del componente no se encuentra en el archivo .h (o, si lo hay, lo encontrará tan pronto como intente compilar el archivo .c).
Es decir, incluir en el siguiente orden:
- El encabezado prototipo / interfaz para esta implementación (es decir, el archivo .h / .hh que corresponde a este archivo .cpp / .cc).
- Otros encabezados del mismo proyecto, según sea necesario.
- Encabezados de otras bibliotecas no estándar, que no son del sistema (por ejemplo, Qt, Eigen, etc.).
- Encabezados de otras bibliotecas "casi estándar" (por ejemplo, Boost)
- Cabeceras estándar de C ++ (por ejemplo, iostream, funcional, etc.)
- Encabezados C estándar (por ejemplo, cstdint, dirent.h, etc.)
Si alguno de los encabezados tiene un problema con ser incluido en este orden, corríjalos (si es el suyo) o no los use. Boicotear las bibliotecas que no escriben encabezados limpios.
La guía de estilo C ++ de Google sostiene casi lo contrario, sin ninguna justificación; Personalmente tiendo a favorecer el enfoque de Lakos.
No creo que haya un pedido recomendado, siempre y cuando se compile! Lo que es molesto es cuando algunos encabezados requieren que se incluyan otros encabezados primero ... Eso es un problema con los encabezados, no con el orden de los incluidos.
Mi preferencia personal es ir de local a global, cada subsección en orden alfabético, es decir:
- archivo h correspondiente a este archivo cpp (si corresponde)
- encabezados del mismo componente,
- encabezados de otros componentes,
- Cabeceras del sistema.
Mi razón para 1. es que debe probar que cada encabezado (para el cual hay un cpp) puede ser #include
d sin requisitos previos. Y el resto parece fluir lógicamente de allí.
Para agregar mi propio ladrillo a la pared.
- Cada encabezado debe ser autosuficiente, que solo se puede probar si se incluye primero al menos una vez
- Uno no debe modificar erróneamente el significado de un encabezado de terceros introduciendo símbolos (macro, tipos, etc.)
Así que usualmente voy así:
// myproject/src/example.cpp
#include "myproject/example.h"
#include <algorithm>
#include <set>
#include <vector>
#include <3rdparty/foo.h>
#include <3rdparty/bar.h>
#include "myproject/another.h"
#include "myproject/specific/bla.h"
#include "detail/impl.h"
Cada grupo separado por una línea en blanco del siguiente:
- Encabezado correspondiente a este archivo cpp primero (comprobación de validez)
- Cabeceras del sistema
- Encabezados de terceros, organizados por orden de dependencia.
- Encabezados de proyecto
- Proyecto encabezados privados
También tenga en cuenta que, aparte de los encabezados del sistema, cada archivo está en una carpeta con el nombre de su espacio de nombres, simplemente porque es más fácil rastrearlos de esta manera.
Primero incluya el encabezado correspondiente a .cpp ... en otras palabras, source1.cpp
debe incluir source1.h
antes de incluir cualquier otra cosa. La única excepción que se me ocurre es cuando utilizo MSVC con encabezados precompilados, en cuyo caso, se ve obligado a incluir stdafx.h
antes que cualquier otra cosa.
Razonamiento: la inclusión de source1.h
antes de cualquier otro archivo garantiza que puede estar solo sin sus dependencias. Si source1.h
adquiere una dependencia en una fecha posterior, el compilador lo alertará inmediatamente para que agregue las declaraciones de reenvío requeridas a source1.h
. Esto a su vez asegura que los encabezados puedan ser incluidos en cualquier orden por sus dependientes.
Ejemplo:
fuente1.h
class Class1 {
Class2 c2; // a dependency which has not been forward declared
};
source1.cpp
#include "source1.h" // now compiler will alert you saying that Class2 is undefined
// so you can forward declare Class2 within source1.h
...
Usuarios de MSVC: Recomiendo utilizar encabezados precompilados. Por lo tanto, mueva todas las directivas #include
para encabezados estándar (y otros encabezados que nunca cambiarán) a stdafx.h
.
Sigo dos reglas simples que evitan la gran mayoría de problemas:
- Todos los encabezados (y, de hecho, los archivos de origen) deben incluir lo que necesitan. No deben confiar en sus usuarios incluyendo cosas.
- Como complemento, todos los encabezados deben incluir guardias para que no se incluyan varias veces por una aplicación demasiado ambiciosa de la regla 1 anterior.
También sigo las pautas de:
- Incluya los encabezados del sistema primero (stdio.h, etc.) con una línea divisoria.
- Agruparlos lógicamente.
En otras palabras:
#include <stdio.h>
#include <string.h>
#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"
Aunque, siendo directrices, eso es algo subjetivo. Las reglas, por otro lado, las aplico con rigidez, incluso hasta el punto de proporcionar archivos de encabezado ''envoltorios'' con guardas de inclusión y agrupaciones incluidas si algún desarrollador de terceros molesto no se suscribe a mi visión :-)
Yo recomiendo:
- El encabezado del módulo .cc que estás construyendo. (Ayuda a garantizar que cada encabezado de su proyecto no tenga dependencias implícitas de otros encabezados de su proyecto).
- C archivos del sistema.
- Archivos del sistema C ++.
- Plataforma / OS / otros archivos de cabecera (por ejemplo, win32, gtk, openGL).
- Otros archivos de cabecera de su proyecto.
Y, por supuesto, el orden alfabético dentro de cada sección, cuando sea posible.
Siempre use declaraciones hacia adelante para evitar #include
s innecesarios en sus archivos de encabezado.