macro from dev define c++ macros linker

from - c++ define macro



El uso de guardias de doble inclusiĆ³n en C++ (5)

Así que recientemente tuve una discusión donde trabajo, en la que cuestionaba el uso de un protector de doble inclusión sobre un solo guardia. Lo que quiero decir con doble guardia es el siguiente:

Archivo de encabezado, "header_a.hpp":

#ifndef __HEADER_A_HPP__ #define __HEADER_A_HPP__ ... ... #endif

Al incluir el archivo de encabezado en cualquier lugar, ya sea en un encabezado o en un archivo de origen:

#ifndef __HEADER_A_HPP__ #include "header_a.hpp" #endif

Ahora entiendo que el uso de la protección en los archivos de encabezado es para evitar la inclusión múltiple de un archivo de encabezado ya definido, es común y está bien documentado. Si la macro ya está definida, el compilador ve todo el archivo de encabezado como "en blanco" y se evita la doble inclusión. Suficientemente simple.

El problema que no entiendo es usar #ifndef __HEADER_A_HPP__ y #endif alrededor del #include "header_a.hpp" . El compañero de trabajo me dijo que esto agrega una segunda capa de protección a las inclusiones, pero no veo cómo esa segunda capa es incluso útil si la primera capa cumple su función (¿o no?).

El único beneficio que puedo obtener es que evita que el enlazador se moleste en encontrar el archivo. ¿Está destinado a mejorar el tiempo de compilación (que no se mencionó como un beneficio), o hay algo más en el trabajo aquí que no estoy viendo?


El único beneficio que puedo obtener es que evita que el enlazador se moleste en encontrar el archivo.

El enlazador no se verá afectado de ninguna manera.

Podría evitar que el preprocesador se moleste en encontrar el archivo, pero si se define la protección, eso significa que ya ha encontrado el archivo. Sospecho que si el tiempo previo al proceso se reduce, el efecto sería bastante mínimo, excepto en la monstruosidad más recursivamente incluida patológicamente.

Tiene el inconveniente de que si alguna vez se cambia el protector (por ejemplo, debido a un conflicto con otro protector), todos los condicionales antes de las directivas de inclusión deben cambiarse para que funcionen. Y si algo más usa la protección anterior, entonces los condicionales deben cambiarse para que la directiva de inclusión funcione correctamente.

PS __HEADER_A_HPP__ es un símbolo reservado a la implementación, por lo que no es algo que pueda definir. Usa otro nombre para el guardia.


Aunque hay personas que argumentan en contra, en la práctica ''#pragma once'' funciona perfectamente y los principales compiladores (gcc / g ++, vc ++) lo admiten.

Entonces, sea cual sea la argumentación purista que la gente está difundiendo, funciona mucho mejor:

  1. Rápido
  2. Sin mantenimiento, sin problemas con la misteriosa no inclusión porque copió una bandera antigua
  3. Línea única con significado obvio versus líneas crípticas extendidas en el archivo

Entonces simplemente pon:

#pragma once

al comienzo del archivo, y eso es todo. Optimizado, mantenible y listo para funcionar.


Estoy bastante seguro de que es una mala práctica agregar otro protector de inclusión como:

#ifndef __HEADER_A_HPP__ #include "header_a.hpp" #endif

Aquí hay algunas razones de por qué:

  1. Para evitar la doble inclusión, es suficiente agregar un protector de inclusión habitual dentro del archivo de encabezado. Hace bien el trabajo. Otra protección incluida en el lugar de inclusión solo ensucia el código y reduce la legibilidad.

  2. Agrega dependencias innecesarias. Si cambia incluir protector dentro del archivo de encabezado, debe cambiarlo en todos los lugares donde se incluye el encabezado.

  3. Definitivamente no es la operación más costosa que compara todo el proceso de compilación / vinculación, por lo que difícilmente puede reducir el tiempo total de construcción.

  4. Cualquier compilador que valga la pena ya optimiza los archivos de inclusión de todo el archivo .


La razón para poner guardias de inclusión en el archivo de encabezado es evitar que el contenido del encabezado se arrastre a una unidad de traducción más de una vez. Esa es una práctica normal y establecida desde hace mucho tiempo.

La razón para colocar protectores de inclusión redundantes en un archivo fuente es para evitar tener que abrir el archivo de encabezado que se incluye, y en los viejos tiempos, eso podría acelerar significativamente la compilación. En estos días, abrir un archivo es mucho más rápido de lo que solía ser; Además, los compiladores son bastante inteligentes al recordar qué archivos ya han visto, y entienden el idioma de incluir guardia, por lo que pueden descubrir por sí mismos que no necesitan abrir el archivo nuevamente. Eso es un poco agitar las manos, pero la conclusión es que esta capa adicional ya no es necesaria.

EDITAR: otro factor aquí es que compilar C ++ es mucho más complicado que compilar C, por lo que lleva mucho más tiempo, lo que hace que el tiempo dedicado a abrir los archivos sea una parte más pequeña y menos significativa del tiempo que lleva compilar una unidad de traducción.


Los compiladores más antiguos en plataformas más tradicionales (mainframe) (estamos hablando a mediados de la década de 2000 aquí) no solían tener la optimización descrita en otras respuestas, por lo que realmente redujeron significativamente el tiempo de preprocesamiento al tener que volver a leer los archivos de encabezado que ya se han incluido (teniendo en cuenta que en un proyecto grande, monolítico y empresarial, se incluirán MUCHOS archivos de encabezado). Como ejemplo, he visto datos que indican una aceleración de 26 veces para un archivo con 256 archivos de encabezado, cada uno de los cuales incluye los mismos 256 archivos de encabezado en el compilador VisualAge C ++ 6 para AIX (que data de mediados de la década de 2000). Este es un ejemplo bastante extremo, pero este tipo de aceleración se suma.

Sin embargo, todos los compiladores modernos, incluso en plataformas de mainframe como AIX y Solaris, realizan una optimización suficiente para la inclusión de encabezados que la diferencia en estos días realmente es insignificante. Por lo tanto, no hay una buena razón para tenerlos más.

Sin embargo, esto explica por qué algunas compañías aún se aferran a la práctica, porque relativamente recientemente (al menos en términos de edad de base de código C / C ++) todavía valió la pena para proyectos monolíticos muy grandes.