C/C++ incluye orden de archivos de encabezado [cerrado]
¿Qué orden deben especificarse los archivos de inclusión, es decir, cuáles son las razones para incluir un encabezado antes que otro?
Por ejemplo, ¿los archivos del sistema, STL y Boost van antes o después de los archivos de inclusión locales?
¡No creo que haya un orden recomendado, siempre y cuando se compile! Lo que es molesto es cuando algunos encabezados requieren que otros encabezados se incluyan primero... Eso es un problema con los encabezados en sí, no con el orden de inclusión.
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,
- encabezados del sistema.
Mi razonamiento para 1. es que debería demostrar que cada encabezado (para el cual hay un cpp) se puede analizar #include
sin requisitos previos (técnicamente hablando: el encabezado es "autónomo"). Y el resto parece fluir lógicamente a partir de ahí.
Lo más importante a tener en cuenta es que sus encabezados no deben depender de que se incluyan primero otros encabezados. 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 C++ a gran escala" de Lakos:
Los errores de uso latentes se pueden evitar asegurándose de que el archivo .h de un componente se analice por sí solo, sin declaraciones ni definiciones proporcionadas externamente... Incluir el archivo .h como la primera línea del archivo .c garantiza que ninguna pieza crítica falta información intrínseca a la interfaz física del componente en el archivo .h (o, si la hay, lo descubrirá tan pronto como intente compilar el archivo .c).
Es decir incluir en el siguiente orden:
- El encabezado del 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 y ajenas al sistema (por ejemplo, Qt, Eigen, etc.).
- Encabezados de otras bibliotecas "casi estándar" (por ejemplo, Boost)
- Encabezados 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 problemas para incluirse en este pedido, corríjalo (si es suyo) o no lo use. Boicotee las bibliotecas que no escriban encabezados limpios.
La guía de estilo C++ de Google sostiene casi lo contrario, sin justificación alguna; Personalmente tiendo a favorecer el enfoque de Lakos.
Sigo dos reglas simples que evitan la gran mayoría de problemas:
- Todos los encabezados (y, de hecho, cualquier archivo fuente) deben incluir lo que necesitan. No deberían confiar en que sus usuarios incluyan cosas.
- Como complemento, todos los encabezados deben incluir guardias para que no se incluyan varias veces debido a la aplicación demasiado ambiciosa de la regla 1 anterior.
También sigo las pautas de:
- Incluya primero los encabezados del sistema (stdio.h, etc.) con una línea divisoria.
- Agrúpelos 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, al ser pautas, eso es algo subjetivo. Las reglas, por otro lado, las aplico rígidamente, incluso hasta el punto de proporcionar archivos de encabezado 'contenedores' con protecciones de inclusión e inclusiones agrupadas si algún desarrollador externo desagradable no se suscribe a mi visión :-)