¡Nuevo en C ++! Entonces estaba leyendo esto: http://www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/
Guardias de cabecera
Debido a que los archivos de encabezado pueden incluir otros archivos de encabezado, es posible terminar en una situación en la que un archivo de encabezado se incluye varias veces.
Entonces hacemos directivas de preprocesador para evitar esto. Pero no estoy seguro: ¿por qué el compilador no puede ... no importar lo mismo dos veces?
Dado que los protectores de encabezado son opcionales (pero aparentemente una buena práctica), casi me hace pensar que hay escenarios en los que desea importar algo dos veces. Aunque no puedo pensar en tal escenario en absoluto. ¿Algunas ideas?
#pragma once
que le dice al compilador que solo incluya ese archivo una vez.Respuestas:
Pueden, como lo muestran los nuevos idiomas que lo hacen.
Pero se tomó una decisión de diseño hace todos esos años (cuando el compilador de C era múltiples etapas independientes) y ahora para mantener la compatibilidad, el preprocesador debe actuar de cierta manera para asegurarse de que el código antiguo se compila como se esperaba.
Como C ++ hereda la forma en que procesa los archivos de encabezado de C, mantuvo las mismas técnicas. Estamos respaldando una antigua decisión de diseño. Pero cambiar la forma en que funciona es demasiado arriesgado y podría romper mucho código. Así que ahora tenemos que enseñar a los nuevos usuarios del lenguaje cómo usar los guardias de inclusión.
Hay un par de trucos con archivos de encabezado donde los incluyó deliberadamente varias veces (esto en realidad proporciona una característica útil). Sin embargo, si rediseñamos el paradigma desde cero, podríamos hacer que esta sea la forma no predeterminada de incluir archivos.
fuente
De lo contrario, no sería tan expresivo, dado que optaron por mantener la compatibilidad con C y, por lo tanto, continuar con un preprocesador en lugar de un sistema de embalaje tradicional.
Una cosa que me viene a la mente es que tenía un proyecto que era una API. Tenía dos archivos de encabezado
x86lib.h
yx86lib_internal.h
. Debido a que el interno era enorme, separé los bits "públicos" a x86lib.h para que los usuarios no tuvieran que reservar tiempo adicional para la compilación.Esto introdujo un problema divertido con las dependencias, así que terminé teniendo un flujo que fue así en x86lib_internal
No diría que fue la mejor manera de hacerlo, pero logró lo que quería.
fuente
Una dificultad con la exclusión automática de encabezado duplicado es que el estándar C es relativamente silencioso sobre el tema de lo que significa incluir nombres de archivos. Por ejemplo, suponga que el archivo principal que se está compilando contiene directivas
#include "f1.h"
y#include "f2.h"
, y los archivos encontrados para esas directivas contienen ambos#include "f3.h"
. Sif1.h
yf2.h
están en directorios diferentes, pero se encontraron buscando rutas de acceso incluidas, entonces no estaría claro si las#include
directivas dentro de esos archivos tenían la intención de cargar el mismof3.h
archivo o diferentes.Las cosas empeoran aún más si se agregan las posibilidades de incluir archivos que incluyen rutas relativas. En algunos casos en los que los archivos de encabezado utilizan rutas relativas para las directivas de inclusión anidadas, y donde se desea evitar realizar cambios en los archivos de encabezado suministrados, puede ser necesario duplicar un archivo de encabezado en varios lugares dentro de la estructura de directorios de un proyecto. Aunque existen múltiples copias físicas de ese archivo de encabezado, deben considerarse semánticamente como si fueran un solo archivo.
Si la
#pragma once
directiva permitiera seguir un identificadoronce
, con la semántica de que el compilador debería omitir el archivo si el identificador coincide con uno de una#pragma once
directiva encontrada anteriormente , entonces la semántica no sería ambigua; un compilador que podría decir que una#include
directiva cargaría el mismo#pragma once
archivo etiquetado que uno anterior, podría ahorrar un poco de tiempo omitiendo el archivo sin abrirlo nuevamente, pero dicha detección no sería semánticamente importante ya que el archivo se omitiría si o no el nombre de archivo fue reconocido como una coincidencia. Sin embargo, no conozco ningún compilador que funcione de esa manera. Hacer que un compilador observe si un archivo coincide con el patrón#ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing following
y tratar tal cosa como equivalente al anterior#pragma once someIdentifier
sisomeIdentifier
permanece definido, es esencialmente tan bueno.fuente