Post on 28-Dec-2015
ARCHIVOS DE CABECERA
Se denomina header file, al español fichero cabecera, o include file, al español ficherode
inclusión, en ciencias de computación, especialmente en el ámbito de los lenguajesde
programación C y C++, al archivo, normalmente en forma de código fuente, que
elcompilador incluye de forma automática al procesar algún otro archivo
fuente.Típicamente los programadores especifican la inclusión de los header files por
mediode pragmas al comienzo (head o cabecera) de otro archivo fuente.Un header file
contiene, normalmente, una declaración directa de clases, subrutinas,variables, u otros
identificadores. Aquellos programadores que desean declararidentificadores estándares
en más de un archivo fuente pueden colocar esosidentificadores en un único header file,
que se incluirá cuando el código que contienesea requerido por otros archivos.Si se adopta
el modelo modular entonces se querrá tener para cada módulo lasdefiniciones de las
variables, los prototipos de las funciones, etc. Sin embargo, ¿quésucede si varios módulos
necesitan compartir tales definiciones? En tal caso, lo mejores centralizar las definiciones
en un archivo, y compartir el archivo entre los módulos.Tal archivo es usualmente llamado
un archivo cabecera .Por convención estos archivos tienen el sufijo .h Se han revisado ya
algunos archivos cabecera de la biblioteca estándar, por ejemplo:
#include <stdio.h>
Se pueden definir los propios archivos cabecera y se pueden incluir en el programacomo
se muestra enseguida:
#include "mi_cabecera.h"
Los archivos cabecera por lo general sólo contienen definiciones de tipos de
datos,prototipos de funciones y comandos del preprocesador de C
FUNCIONES DE BIBLIOTECAS
El lenguaje C, C++ contiene numerosas funciones, cuando se emplean funciones deesta
biblioteca estándar, se incrementa la transportabilidad de los programas.C ofrece un
conjunto de funciones estándar que dan soporte a las operaciones que seutilizan con más
frecuencia. Estas funciones están agrupadas en bibliotecas. Parautilizar cualquiera de las
funciones que forman parte de las bibliotecas estándar de C,sólo hace falta realizar una
llamada a dicha función.Los grupos de funciones estándar más comunes son:
Entrada/Salida estándar
Matemáticas
De conversión
Diagnostico
De manipulación de memoria
Control de proceso
Ordenación
Directorios
Fecha y hora
Búsqueda
Manipulación de cadenas
Gráficos
Tipos de ficheros
Los ficheros de cabecera del proyecto se llamarán fichero.h (si trabajamos en C) o
fichero.hh (si trabajamos en C++) (también sería correcto el uso de fichero.hpp para C++)
Los ficheros con el codigo de las funciones no inline se llamará fichero.c (si trabajamos en
C) o fichero.cc (si trabajamos en C++) (también sería correcto el uso de fichero.cpp para C+
+)
Los ficheros con el codigo de las funciones inline se llamará fichero.ic (si trabajamos en C)
o fichero.icc (si trabajamos en C++) (también sería correcto el uso de fichero.ipp)
El separar las funciones inline (funciones definidas en una sóla línea) de las demás
funciones se debe a que algunos debuggers (y más raramente algunos compiladores) no
manejan bien las funciones inline.
Separando las funciones inline en un fichero aparte, podemos conseguir que se incluyan
en los ficheros de cabecera o en los ficheros fuente, según nosotros deseemos de acuerdo
a directivas de compilación.
A continuación se muestra en un ejemplo como se haría...
// At the end of fichero.hh
#if !defined(DEBUG_MODE)
#include <fichero.icc>
#endif
// At the end of fichero.cc
#if defined(DEBUG_MODE)
#include <fichero.icc>
#endif
Con este ejemplo conseguimos que si se compila en modo debug (definiendo
DEBUG_MODE) las funciones inline (funcion.icc) se incluiran en el fichero.hh, mientras que
en el modo normal se incuirian en el fichero.cc
[subir]
10.2 Nombres de los ficheros
Para C en cada fichero de una librería tiene que haber funciones realcionadas con el
mismo fin, y el nombre sería el apropiado para poder identificar el fin de estas funciones
(por ejemplo funcionesFecha.c para recopilar funciones de manejo de fechas).
Para C++ en cada fichero de una librería tiene que haber solamente una clase, y el nombre
del fichero sería el mismo que el de la clase (por ejemplo CMiClase.cc para la
implementación de la clase CMiClase).
[subir]
10.3 Estructura de los ficheros
Los ficheros de cabecera (fichero.h, fichero.hh, fichero.hpp) tendrían que tener una
estructura como la siguiente:
Cabecera del fichero.
Includes si es necesario alguno (se aconseja que en los ficheros de cabecera no vaya
ningún fichero include o el mínimo número imprescindible de ellos).
Primero los includes del sistema (si hace falta alguno)
Después los includes propios del proyecto (si hace falta alguno)
Constantes simbólicas y definiciones de macros que se vayan a utilizar en otros
m&ocaute;dulos que incluyan este.
Definición de tipos que se vayan a utilizar en otros módulos que incluyan este.
Prototipos de las funciones del módulo que puedan ser utilizadas desde otro módulo.
Declaración de las clases (C++) del módulo que puedan ser utilizadas desde otro módulo.
Los ficheros fuente (fichero.c, fichero.cc, fichero.cpp) tendrían que tener una estructura
como la siguiente:
Cabecera del fichero.
Includes necesarios para el módulo.
Primero los includes del sistema.
Después los includes propios del proyecto.
Constantes simbólicas y dfiniciones de macros que solamente vayan a utilizarse en este
módulo.
Definición de tipos que se vayan a utilizar solamente en este módulo.
Variables globales usadas en el módulo.
Primero las declaradas en otros módulos distintos, con la palabra reservada extern.
Después las declaradas en este m&odulo.
Prototipos de las funciones del módulo que sólo se usen en este módulo.
Declaración de las clases (C++) del módulo que sólo se usen en este módulo.
Implementación de las funciones del módulo.
La función principal (main()) tiene que ser la primera, las demás estarán ordenadas por
orden de aparición en la función principal o por orden de llamada, u organizándolas por su
uso o finalidad.
Es aconsejable que las implementaciones estén en el mismo orden que sus prototipos.
Implementación de los métodos de las clases (C++).
Es aconsejable que las implementaciones de los métodos estén en el mismo orden en que
aparecen en las declaraciones de las clases.
Los ficheros que contienen las funciones inline (fichero.ic, fichero.icc, fichero.ipp)
solamente contendrán el código de las funciones inline y tendrán una estructura como la
siguiente:
Cabecera del fichero
Código de las funciones inline.
Se aconseja que estén en el mismo orden en que se declaran en el fichero de cabecera.
[subir]
10.4 Cabeceras de los ficheros
Todos los ficheros tienen que incluir una cabecera que indique los siguientes campos.
Nombre del fichero
Finalidad o uso del módulo (incluyendo los argumentos si en este fichero se encuentra la
función main).
Variables globales afectadas (si las hay).
Nombre del autor y fecha de última modificación.
Historial de moficiaciones, con fecha, motivo y nombre del autor.
[subir]
10.5 Ficheros de cabecera (*.h)
Todos los ficheros de cabecera tienen que tener un mecanismo para impedir que sean
incluidos más de una vez (lo mismo les pasaría a los ficheros de las funciones inline).
Por ejemplo, el siguiente metodo valdría:
#ifndef __FICHERO_H__
#define __FICHERO_H__
// __FICHERO_H__ sería un identificador propio de este fichero (fichero.h)
// ya que lo he construido con el nombre del fichero
...
// Aquí iría todo el contenido del fichero
...
#endif
Todos los ficheros de cabecera incluidos en los ficheros deben serlo exclusivamente por
que se usan.
Hay que evitar la inclusión de ficheros de cabecera que no se usan, por legibilidad, puede
complicar la compilación y el linkado innecesariamente.
Los includes de librerías própias del sistema se realiza indicando el nombre entre
caracteres < y >. Por ejemplo:
#include <stdio.h>
Los includes propios del proyecto se realizarán indicando el nombre entre caracteres ". Por
ejemplo:
#include "CMiClase.hh.h"
Conveciones para los ficheros de cabecera
Cuando se crea una struct que contiene funciones miembro, se está creando un nuevo tipo
de dato. En general, se intenta que ese tipo sea fácilmente accesible. En resumen, se
quiere que la interfaz (la declaración) esté separada de la implmentación (la definición de
los métodos) de modo que la implementación pueda cambiar sin obligar a recompilar el
sistema completo. Eso se consigue poniendo la declaración del nuevo tipo en un fichero de
cabecera.
Cuando yo aprendí a programar en C, el fichero de cabecera era un misterio para mi.
Muchos libros de C no hacen hincapié, y el compilador no obliga a hacer la declaración de
las funciones, así que parecía algo opcional la mayor parte de las veces, excepto cuando se
declaraban estrucutras. En C++ el uso de los ficheros de cabecera se vuelve claro como el
cristal. Son prácticamente obligatorios para el desarrollo de programas sencillos, y en ellos
podrá información muy específica: declaraciones. El fichero de cabecera informa al
compilador de lo que hay disponible en la librería. Puede usar la librería incluso si sólo se
dispone del fichero de cabecera y el fichero objeto o el fichero de librería; no necesita
disponer del código fuente del fichero cpp. En el fichero de cabecera es donde se guarda la
especificación de la interfaz.
Aunque el compilador no lo obliga, el mejor modo de construir grandes proyectos en C es
usar librerías; colecciones de funciones asociadas en un mismo módulo objeto o librería, y
usar un fichero de cabecera para colocar todas las declaraciones de las funciones. Es de
rigor en C++, Podría meter cualquier función en una librería C, pero el tipo abstracto de
dato C++ determina las funciones que están asociadas por medio del acceso común a los
datos de una struct. Cualquier función miembro debe ser declarada en la declaración de la
struct; no puede ponerse en otro lugar. El uso de librerías de funciones fue fomentado en
C y institucionalizado en C++.
4.7.1. Importancia de los ficheros de cabecera
Cuando se usa función de una librería, C le permite la posibilidad de ignorar el fichero de
cabecera y simplemente declarar la función a mano. En el pasado, la gente hacía eso a
veces para acelerar un poquito la compilación evitando la tarea de abrir e incluir el fichero
(eso no supone ventaja alguna con los compiladores modernos). Por ejemplo, la siguiente
es una declaración extremadamente vaga de la función printf() (de <stdio.h>):
printf(...);
Estos puntos suspensivos [49] especifican una lista de argumentos variable [50], que dice:
la printf() tiene algunos argumentos, cada uno con su tipo, pero no se sabe cuales.
Simplemente, coge los argumentos que veas y aceptalos. Usando este tipo de declaración,
se suspenden todas las comprobaciones de errores en los argumentos.
Esta práctica puede causar problemas sutiles. Si declara funciones «a mano», en un fichero
puede cometer un error. Dado que el compilador sólo verá las declaraciones hechas a
mano en ese fichero, se adaptará al error. El programa enlazará correctamente, pero el uso
de la función en ese fichero será defectuoso. Se trata de un error difícil de encontrar, y que
se puede evitar fácilmente usando el fichero de cabecera correspondiente.
Si se colocan todas las declaraciones de funciones en un fichero de cabecera, y se incluye
ese fichero allí donde se use la función se asegurará una declaración consistente a través
del sistema completo. También se asegurará de que la declaración y la definición
corresponden incluyendo el fichero de cabecera en el fichero de definición.
Si declara una struct en un fichero de cabecera en C++, debe incluir ese fichero allí donde
se use una struct y también donde se definan los métodos de la struct. El compilador de
C++ devolverá un mensaje de error si intenta llamar a una función, o llamar o definir un
método, sin declararla primero. Imponiendo el uso apropiado de los ficheros de cabecera,
el lenguaje asegura la consistencia de las librerías, y reduce el número de error forzando
que se use la misma interface en todas partes.
El fichero de cabecera es un contrato entre el programador de la librería y el que la usa. El
contrato describe las estructuras de datos, expone los argumentos y valores de retorno
para las funciones. Dice, «Esto es lo que hace mi librería». El usuario necesita parte de esta
información para desarrollar la aplicación, y el compilador necesita toda ella para generar
el código correcto. El usuario de la struct simplemente incluye el fichero de cabecera, crea
objetos (instancias) de esa struct, y enlaza con el módulo objeto o librería (es decir, el
código compilado)
El compilador impone el contrato obligando a declarar todas las estruturas y funciones
antes que puedan ser usadas y, en el caso de métodos, antes de ser definidos. De ese
modo, se le obliga a poner las declaraciones en el fichero de cabecera e incluirlo en el
fichero en el que se definen los métodos y en los ficheros en los que se usen. Como se
incluye un único fichero que describe la librería para todo el sistema, el compilador puede
asegurar la consistencia y evitar errores.
Hay ciertos asuntos a los que debe prestar atención para organizar su código
apropiadamente y escribir ficheros de cabecera eficaces. La regla básica es «únicamente
declaraciones», es decir, sólo información para el compiladore pero nada que requiera
alojamiento en memoria ya sea generando código o creando variables. Esto es así porque
el fichero de cabecera normalmente se incluye en varias unidades de traducción en un
mismo proyecto, y si el almacenamiento para un identificador se pide en más de un sitio,
el enlazador indicará un error de definición múltiple (ésta es la regla de definición única de
C++: Se puede declarar tantas veces como se quiera, pero sólo puede haber una definición
real para cada cosa).
Esta norma no es completamente estricta. Si se define una variable que es «file static»
(que tiene visibilidad sólo en un fichero) dentro de un fichero de cabecera, habrá múltiples
instancias de ese dato a lo largo del proyecto, pero no causará un colisión en el enlazador
[51]. Básicamente, debe evitar cualquier cosa en los ficheros de cabecera que pueda
causar una ambigüedad en tiempo de enlazado.
Cómo usar #include en C y C++
La directiva de preprocesador #include se usa en los lenguajes C y C++para “incluir” las declaraciones de otro fichero en la compilación. Esta directiva no tiene más misterio para proyectos pequeños. En cambio, puede ayudar aprovechar bien esta directiva en proyectos con un gran número de subdirectorios.
El efecto de #includeCuando el preprocesador encuentra una línea #include "fichero", entonces reemplaza esta línea por el fichero incluido. Así procede con todas las directivas de inclusión – también en aquellas anidadas en los fichero ya a su vez incluidos. Es decir, existe un sólo fichero grande tras la precompilación.
No obstante, esta unión de varios ficheros no tiene lugar físicamente. Lo que sucede es que se interrumpe la compilación del fichero actual, se compila el fichero incluido y, tras compilarlo, se continúa con el primero. Por eso, el compilador puede decirnos, en qué fichero tuvo lugar un error de compilación.
En cambio, conviene tener esta idea del fichero único en mente, porque a veces ayuda a encontrar errores. Uno muy típico es olvidarse el punto y coma tras la declaración de una clase.
En este caso hay una declaración de clase en el fichero incluido:
class MiClase {}En el segundo puede haber algo así:
12
#include "mi_clase.h"MiClase miInstancia;
En este ejemplo, el compilador se quejará de que aquí no se puede definir un nuevo tipo en la línea de MiClase miInstancia aunque esta línea es correcta. El error verdadero es la falta del ; en el fichero incluido. Lo que el compilador realmente ve es
class MiClase {} MiClase miInstancia;No obstante, el programador no lo ve, porque el código está distribuido sobre dos fichero y el error se produce en el correcto.
La precompilación sólo modifica el código a nivel textual. No entiende del sintaxis del lenguaje. Por eso es posible distribuir el código de forma arbitraria. Por ejemplo, el siguiente ejemplo compilaría.
Fichero incluido
12
{ int
Fichero principal
1234
void main(void)#include "fichero_incluido" a;}
Esto es así porque el compilador ve el conunto
12345
void main(void){ int a;}
La posición del #include
Lo habitual es posicionar las inclusiones al inicio de cada fichero. Esto tiene sentido, porque se suele requerir declaraciones básices antes de declarar clases más complejas. Mi lugar preferido en los ficheros de cabecera es tras el guardián de inclusión múltiple.
1234567
// Guardian de inclusión múltiple#ifndef FICHERO_YA_INCLUIDO#define FICHERO_YA_INCLUIDO
#include "declaraciones_basicas.h"
#endifAsí se evita que un compilador poco sofisticado abre otra vez el mismo conjunto de ficheros cuando se inluye un fichero de cabecera dos o más veces.
En los ficheros de definición (los .c o .cpp), los guardianes de inclusión múltiple no hacen falta. No obstante, puede haber una restricción importante cuando se usan cabeceras precompiladas. En este caso, todos los ficheros fuente deben incluir primero el mismo fichero de cabecera – que es aquello que define la cabecera precompilada. El compilador de C++ de Borland permite varios ficheros de cabecera para la definición de una cabecera precompilada. Estas inclusiones deben ser lor primeros ficheros incluidos y se deben incluir en el mismo orden.
Puede darse el caso de no poner las inclusiones en el inicio de un fichero. Esto es frecuente en los fichero que se podrían denominar “programados en directivas de precompilación”. Normalmente se trata de ficheros de cabeceras con definiciones muy básicas como ajustes a la plataforma empleada. Por ejemplo, en medio de un fichero “definiciones_basicas.h” puede haber unas líneas
123456789
#if PLATAFORMA_ES_LINUX#include "funcionalidad_gratis.h"#elif PLATAFORMA_ES_MICROSOFT_WINDOWS#include "funcionalidad_cara.h"#elif PLATAFORMA_ES_APPLE#include "funcionalidad_muy_cara.h"#else#error Esta plataforma no está soportada#endif
La diferencia entre “” y <>La directiva #include existe en dos versiones. En una se pone el nombre de fichero entre comillas, en la otra entre paréntesis angulares (el signo menor y mayor como “comillas”).
12
#include "fichero_con_comillas.h"#include <fichero_entre_menor_y_mayor.h>
La versión con los paréntesis angulares busca los ficheros en todos los directorios que se han especificado en la llamada al compilador – normalmente con la opción “-I”. Estos directorios se suelen rastrear por el fichero incluido en el orden en que aparecen en la línea de comando.
Cuando se incluye un fichero entre comillas, entonces el compilador busca este fichero primero en el mismo directorio que el fichero actualemente compilado y después en los demás directorios. Es decir, la versión con comillas se diferencia de la versión con paréntesis angulares únicamente por buscar primero en el directorio del fichero compilado. Tras no encontrarlo ahí actúa igual.
Esto muchas veces no es ninguna diferencia, ya que se suelen especificar todos los directorios en la línea de comando del compilador. Así no se suele dar el caso que se puede incluir un fichero con comillas pero no con paréntesis angulares.
Más significativo es el comportamiento ante ficheros con el mismo nombre en distintos directorios. En este caso la versión con comillas da preferencia sobre el fichero en el mismo directorio y esto suele ser el mejor acertado. Aunque sea preferible nombrar ficheros de forma única en un proyecto, es posible que no se pueda evitar tener dos ficheros con el mismo nombre cuando se incluyen varias bibliotecas de terceros.
De ahí se puede deducir que es imperativo incluir cabeceras de la misma biblioteca con comillas. De esta forma se puede asegurar que las cabeceras de una biblioteca se incluyan entre si aunque haya otros con el mismo nombre en uno de los directorios especificados en la línea de comandos.
Además, incluir con comillas puede dar al programador un significado adicional: que este fichero está bajo la custodia de mi equipo de desarrollo. Las cabeceras incluidas con paréntesis angulares son de bibliotecas de terceros. Los primeros ficheros puedo modificar si hace falta, los segundos no.
El orden de las inclusionesEl orden de las directivas #include no importa cuando todos los identificadores del programa son únicos. No obstante, a veces no lo son yconviene generar el error “este identificador ya existe” en nuestro código y no en el código de una biblioteca estándar.
Esto se consigue incluyendo primero las caberas de terceros. Si aparece un error de identificador doble, entonces aparece en la segunda definición – que es la nuestra – y ahí podemos cambiar el nombre del objeto sin problema.
En proyectos realmente grandes puede haber varias bibliotecas de distintas dependencias. Por la misma razón de generar los errores de identificadores dobles en el código más fácilmente modificable, conviene incluir las bibliotecas más básicas primero. Dentro del mismo nivel podemos ordenar los ficheros incluidos de forma alfabética. Esto ayuda a encontrar inclusiones que faltan o sobran.
El siguiente código muestra una secuencia de inclusiones para un fichero “definicion_de_mi_clase.cpp”.
123456789101112131415161718192021222324
// Primero se debe incluir la cabecera de precompilación#include "cabecera_de_precompilacion.h"
// Segundo, incluir la cabecera correspondiente// a este fichero de implementación.// Esto deja más claro, que es la// clase que se implementa aquí.#include "definicion_de_mi_clase.h"
// A continuación inclusiones de la biblioteca estándar.// Se usan paréntesis angulares.#include <vector>
// Inclusiones de otras bibliotecas de terceros#include <wx.h>#include <gl.h>
// Inclusiones de subbibliotecas básicas de// mi proyecto con comillas#include "mis_definiciones_basicas.h"
// Luego las demás inclusiones de mi proyecto#include "clases_auxiliares.h"#include "más_definiciones_para_mi_clase.h"
Usar rutas relativasUna forma de evitar nombres de fichero dobles es incluir ficheros con rutas relativas.
12
#include "definiciones/tipos_básicos.h"#include "funcionalidad/tipos_básicos.h"
La desventaja de esta forma es, que uno debe saber, en qué directorio se encuentra cada cabecera. No obstante, esto suele ser un problema menor. Sin ruta relativa, uno debería poner un prefijo a cada nombre de fichero para evitar nombres dobles. Estos prefijos son típicamente los nombres de los directorios. Es decir, todos los ficheros en el directorio “definiciones” tienen se llaman “definiciones_xxx”. Al final debo saber el nombre de directorio de todas formas.
Los programadores de C++ han copiado de Java la idea de estructurar los directorios como los espacios de nombre. Así, el uso de la claseNombreDeEspacio::Subespacio::MiClase requiere la inclusión del fichero “nombre_de_espacio/subespacio/mi_clase.h”.
El uso de rutas relativas en las inclusiones puede mejorar bastante el orden y reducir la configuración del compilador. Así basta incluir un solo directorio para obtener acceso a todos los componentes de la biblioteca boost, por ejemplo. En cambio, rutas relativas hacen más complicado recolocar ficheros a otros directorios. Y esto puede pasar a menudo en fases tempranos de un proyecto.
Optimizar la velocidad de compilaciónLa inclusión de un sólo fichero normalmente no afecta mucho al tiempo, que el compilador requiere para la compilación de un fichero. Pero esto se cambia si el fichero incluido incluye más ficheros que a su vez incluyen aún más ficheros. Gracias a tantas inclusiones anidadas, una sola inclusión, sí, puede cambiar el tiempo de compilación drásticamente.
Una forma de mejorar la velocidad es utilizar cabeceras precompiladas. Estas cabeceras deben estar incluidas por todos los ficheros de definición y, por eso, debe ser una decisión temprana en un proyecto de utilizarlas o no – al menos si uno quiere evitar añadir esta inclusión en muchos ficheros.
Otra forma es evitar la inclusión de ficheros no necesarios. Normalmente una inclusión adicional no perjudica al resultado de la compilación. Simplemente añade declaraciones que finalmente no se usan. Pero la compilación de estas declaraciones cuesta un tiempo que nos queremos ahorrar.
Para proyectos grandes puede convenir no incluir definiciones de tipos que sólo aparecen como punteros o referencias en los ficheros de cabecera. Esto tipos se pueden introducir con una declaración forward. Sólo en el fichero de definición se incluye entonces la cabecera que define este tipo.
Como ejemplo damos una clase, que guarda un puntero a otra clase. En el fichero de cabecera tenemos
12345678
// Declaración forwardclass OtraClase;
// Declaración de la clase principalclass UnaClase{ OtraClase* dame_un_puntero_a_otra_clase();};
En el fichero de definición tenemos
1234
#include "una_clase.h"#include "otra_clase.h"
OtraClase* UnaClase::dame_un_puntero_a_otra_clase()
5678
{ static OtraClase otraInstancia; return &otraInstancia;}
Cabe señalar que una declaración forward debe tener lugar dentro del nombre de espacio correspondiente.
1234567891011
// Esto no es correctoclass NombreDeEspacio::Subespacio::Clase;
// Se debe hacer la declaración forward asínamespace NombreDeEspacio{ namespace Subespacio { class Clase; }}
ConclusiónComo hemos comprobado, hay bastante que se puede tener en cuenta sobre la directiva #include, cuando se trabaja en proyectos grandes.
La inclusión genera un sólo fichero grande. Tener esto en mente cuando se produce un error de compilación en la primera línea aparamente correcta tras un #include.
Conviene incluir ficheros del propio proyecto con comillas y las cabeceras de terceros con paréntesis angulares para marcar la diferencia entre “propio” y “estándar”.
Ordenando las propias inclusiones al final ayuda a corregir errores de doble definición de identificadores.
Rutas relativas son una buena opción para proyectos con una clara estructura de directorios.
Usar cabeceras precompiladas y evitar incluir ficheros innecesarios – también aprovechando declaraciones forward – puede acelerar el proceso de compilación.