Articulo de referencia

incluir guardia

En los lenguajes de programación C y C++ , un #include guard , a veces llamado macro guard , header guard o file guard , es una forma de evitar el problema de la doble inclusión...

En los lenguajes de programación C y C++ , un #include guard , a veces llamado macro guard , header guard o file guard , es una forma de evitar el problema de la doble inclusión al tratar con la directiva include .

El preprocesador de C procesa directivas de inclusión como incluir textualmente Foo.h y transcluye el código de ese archivo en una copia del archivo principal, a menudo llamada unidad de traducción .#include"Foo.h"

Sin embargo, si una #includedirectiva para un archivo determinado aparece varias veces durante la compilación, el código se duplicará efectivamente en ese archivo. Si el archivo incluido contiene una definición, esto puede provocar un error de compilación debido a la Regla de una Definición , que establece que las definiciones (como la definición de una clase) no pueden duplicarse en una unidad de traducción. #includeLas protecciones evitan esto definiendo una macro de preprocesador cuando se incluye un archivo de cabecera por primera vez. En caso de que ese archivo de cabecera se incluya por segunda vez, la #includeprotección impedirá que se compile el código real dentro de ese archivo de cabecera.

Una alternativa a #includelas directivas de guarda es #pragma once . Esta directiva, no estándar pero ampliamente compatible con los compiladores de C y C++ , tiene el mismo propósito que una #includedirectiva de guarda, pero requiere menos código y no necesita definir una variable.

Los módulos , introducidos en C++20 , eliminan la necesidad de usar #includeguardas, ya que no son gestionados por el preprocesador. Los módulos solo pueden importarse como máximo una vez en una unidad de traducción .

Doble inclusión

Ejemplo

El siguiente código C demuestra un problema real que puede surgir si #includefaltan las protecciones:

Archivo "Abuelo.h"

struct Foo { int member ; };

Archivo "Parent.h"

#incluir "Abuelo.h"

Archivo "Child.c"

#incluir "Abuelo.h" #incluir "Padre.h"

Resultado

// Desde "Grandparent.h" struct Foo { int member ; }; // Desde "Parent.h" struct Foo { int member ; };

Here, the file Child.c has indirectly included two copies of the text in the header fileGrandparent.h. This causes a compilation error, since the structure type Foo will thus be defined twice. In C++, this would be called a violation of the one definition rule.

Use of #include guards

Example

The same code as the previous section is used with the addition of #include guards. The C preprocessor preprocesses the header files, including and further preprocessing them recursively. This will result in a working source file.

File "Grandparent.h"

#ifndef GRANDPARENT_H#define GRANDPARENT_HstructFoo{intmember;};#endif // GRANDPARENT_H

File "Parent.h"

#include"Grandparent.h"

File "Child.c"

#include"Grandparent.h"#include"Parent.h"

Intermediate step

// Contents from "Grandparent.h"#ifndef GRANDPARENT_H // GRANDPARENT_H was not defined#define GRANDPARENT_H// This definition was pastedstructFoo{intmember;};#endif // GRANDPARENT_H// Contents from "Parent.h"#ifndef GRANDPARENT_H // GRANDPARENT_H was already defined#define GRANDPARENT_H// This definition was not pastedstructFoo{intmember;};#endif // GRANDPARENT_H

Result

structFoo{intmember;};

Here, the first inclusion of "Grandparent.h" has the macro GRANDPARENT_H defined. When "Child.c" includes "Grandparent.h" at the second time (while including "Parent.h"), as the #ifndef test returns false, the preprocessor skips down to the #endif, thus avoiding the second definition of struct Foo. The program compiles correctly.

Discussion

Different naming conventions for the guard macro may be used by different programmers. Other common forms of the above example include GRANDPARENT_INCLUDED, CREATORSNAME_YYYYMMDD_HHMMSS (with the appropriate time information substituted), and names generated from a UUID. (However, names starting with one underscore and a capital letter (C and C++) or any name containing double underscore (C++ only), such as _GRANDPARENT_H and GRANDPARENT__H, are reserved to the language implementation and should not be used by the user.[1][2])

Por supuesto, es importante evitar duplicar el mismo nombre de macro include-guard en diferentes archivos de encabezado, ya que incluir el primero impedirá que se incluya el segundo, lo que conllevará la pérdida de cualquier declaración, definición en línea u otros #includeelementos en el segundo encabezado.

Dificultades

Para que #includelos protectores funcionen correctamente, cada uno debe probar y configurar condicionalmente una macro de preprocesador diferente. Por lo tanto, un proyecto que utilice #includeprotectores debe establecer un esquema de nomenclatura coherente para sus protectores de inclusión y asegurarse de que dicho esquema no entre en conflicto con el de ningún archivo de cabecera de terceros que utilice, ni con los nombres de ninguna macro visible globalmente.

Por esta razón, la mayoría de las implementaciones de C y C++ proporcionan una directiva no estándar #pragma once. Esta directiva, insertada al principio de un archivo de cabecera, garantiza que el archivo se incluya solo una vez. El lenguaje Objective-C (que es un superconjunto de C) tiene una #importdirectiva que funciona exactamente igual #include, excepto que incluye cada archivo solo una vez, lo que elimina la necesidad de #includeguardas. [ 3 ]

Otros idiomas

Algunos lenguajes admiten especificar que el código debe incluirse solo una vez, en el archivo que incluye, en lugar de en el archivo incluido (como con los protectores de inclusión de C/C++ y #pragma once):

  • PL/I utiliza la %INCLUDEinstrucción como equivalente a la #includedirectiva de C. IBM Enterprise PL/I también admite la %XINCLUDEinstrucción que "incorporará texto externo al programa fuente si no se ha incluido previamente". (También ofrece una XPROCEDUREinstrucción, similar a una PROCEDUREinstrucción, que ignorará la segunda y las siguientes ocurrencias de un XPROCEDUREcon el mismo nombre). [ 4 ]
  • Directiva de Objective-C#import (ver arriba)
  • PHP [ 5 ]include_once

Véase también

Referencias

  1. Estándar C++ (ISO/IEC 14882) sección 17.4.3.1.2/1
  2. Norma C (ISO/IEC 9899) sección 7.1.3/1.
  3. "Objective C: Definición de clases" . developer.apple.com . 17 de septiembre de 2014. Consultado el 3 de octubre de 2018 .
  4. IBM Corporation (agosto de 2017). Enterprise PL/I para z/OS PL/I para AIX Enterprise PL/I para z/OS Language Reference Versión 5 Release 1 (PDF) . pág. 257. Consultado el 7 de abril de 2022 . 
  5. "include_once (Referencia del lenguaje PHP)" .
  • Incluir optimización de guardia
  • Guardias redundantes incluidos