Saltar al contenido

Archivos de encabezado autosuficientes en C / C ++

Indagamos en diferentes espacios para de esta manera tenerte la respuesta a tu problema, si tienes dificultades puedes dejar tu inquietud y te contestaremos con mucho gusto.

Solución:

Un archivo de encabezado autosuficiente es aquel que no depende del contexto donde se incluye para funcionar correctamente. Si te aseguras de #incluir o definir / declarar todo antes de usarlo, tienes un encabezado autosuficiente.
Un ejemplo de no El encabezado autosuficiente podría ser algo como esto:

----- MyClass.h -----

class MyClass

   MyClass(std::string s);
;

---- MyClass.cpp -----

#include 
#include "MyClass.h"

MyClass::MyClass(std::string s)

En este ejemplo, MyClass.h usos std::string sin primero #incluir. Para que esto funcione, en MyClass.cpp necesitas poner el #include antes de #include "MyClass.h".
Si el usuario de MyClass no puede hacer esto, obtendrá un error que std ::string no esta incluido.

Mantener sus encabezados para que sean autosuficientes a menudo se puede descuidar. Por ejemplo, tiene un encabezado MyClass enorme y le agrega otro método pequeño que usa std ::string. En todos los lugares donde esta clase se usa actualmente, ya está # incluida antes de MyClass.h. luego algún día #incluye MyClass.h como el primer encabezado y de repente tienes todos estos nuevos errores en un archivo que ni siquiera tocaste (MyClass.h)
Manteniendo cuidadosamente sus encabezados para que sean autosuficientes para evitar este problema.

El Goddard Space Flight Center (GSFC) de la NASA ha publicado estándares de programación C y C ++ que abordan este problema.

Suponga que tiene un módulo con un archivo fuente perverse.c y su encabezado perverse.h.

Asegurarse de que un encabezado sea autónomo

Existe una forma muy sencilla de garantizar que un encabezado sea autónomo. En el archivo de origen, el primer encabezado que incluye es el encabezado del módulo. Si se compila así, el encabezado es autónomo (autosuficiente). Si no es así, arregle el encabezado hasta que esté (de manera confiable1) autónomo.

perverso.h

#ifndef PERVERSE_H_INCLUDED
#define PERVERSE_H_INCLUDED

#include 

extern size_t perverse(const unsigned char *bytes, size_t nbytes);

#endif /* PERVERSE_H_INCLUDED */

Casi todos los encabezados deben protegerse contra la inclusión múltiple. (El estandar El encabezado es una excepción explícita a la regla, de ahí el calificador ‘casi’).

perverso.c

#include "perverse.h"
#include    // defines size_t too

size_t perverse(const unsigned char *bytes, size_t nbytes)

    ...etc...

Tenga en cuenta que aunque tradicionalmente se consideraba una buena idea incluir los encabezados estándar antes de los encabezados del proyecto, en este caso, es crucial para la capacidad de prueba que el encabezado del módulo (perverse.h) viene antes que todos los demás. La única excepción que permitiría es incluir un encabezado de configuración antes del encabezado del módulo; sin embargo, incluso eso es dudoso. Si el encabezado del módulo necesita usar (o tal vez solo ‘puede usar’) la información del encabezado de configuración, probablemente debería incluir el encabezado de configuración en sí, en lugar de depender de los archivos fuente que lo usan para hacerlo. Sin embargo, si necesita configurar para qué versión de POSIX solicitar soporte, debe hacerlo antes de que se incluya el primer encabezado del sistema.


Nota al pie 1: El comentario de Steve Jessop a la respuesta de Shoosh es la razón por la que puse el comentario ‘(confiablemente)’ entre paréntesis en mi comentario de ‘arreglarlo’. Él dijo:

Otro factor que dificulta esto es la regla de “los encabezados del sistema pueden incluir otros encabezados” en C ++. Si incluye , entonces es bastante difícil descubrir que ha olvidado incluir en algún encabezado que hace [not] usar [or ]. Compilar el encabezado por sí solo no da errores: es autosuficiente en esta versión de su compilador, pero en otro compilador podría no funcionar.

Consulte también la respuesta de Toby Speight sobre IWYU: incluya lo que usa.


Apéndice: Hacer coincidir estas reglas con los encabezados precompilados de GCC

Las reglas de GCC para encabezados precompilados permiten solo uno de esos encabezados por unidad de traducción, y debe aparecer antes de cualquier token C.

GCC 4.4.1 Manual, §3.20 Uso de encabezados precompilados

Un archivo de encabezado precompilado solo se puede usar cuando se aplican estas condiciones:

  • Solo se puede utilizar un encabezado precompilado en una compilación en particular.
  • No se puede usar un encabezado precompilado una vez que se ve el primer token C. Puede tener directivas de preprocesador antes de un encabezado precompilado; incluso puede incluir un encabezado precompilado desde el interior de otro encabezado, siempre que no haya tokens C antes de #include.
  • […]
  • Todas las macros definidas antes de que se incluya el encabezado precompilado deben definirse de la misma manera que cuando se generó el encabezado precompilado o no deben afectar al encabezado precompilado, lo que generalmente significa que no aparecen en el encabezado precompilado en absoluto.

En una primera aproximación, estas restricciones significan que el encabezado precompilado debe ser el primero en el archivo. Una segunda aproximación señala que si ‘config.h’ solo contiene declaraciones #define, podría aparecer antes del encabezado precompilado, pero es mucho más probable que (a) las definiciones de config.h afecten al resto del código, y (b) el encabezado precompilado debe incluir config.h de todos modos.

Los proyectos en los que trabajo no están configurados para usar encabezados precompilados, y las restricciones definidas por GCC más la anarquía inducida por más de 20 años de mantenimiento intensivo y extensión por parte de una población diversa de codificadores significan que sería muy difícil agregarlos. .

Dados los requisitos divergentes entre las pautas de GSFC y los encabezados precompilados de GCC (y suponiendo que los encabezados precompilados estén en uso), creo que garantizaría la autocontención e idempotencia de los encabezados utilizando un mecanismo separado. Ya hago esto para los proyectos principales en los que trabajo (reorganizar los encabezados para cumplir con las pautas de GSFC no es una opción fácil) y el script que uso es chkhdr, mostrado a continuación. Incluso podría hacer esto como un paso de ‘compilación’ en el directorio de encabezados; asegúrese de que todos los encabezados sean independientes como una regla de ‘compilación’.

secuencia de comandos chkhdr

yo uso esto chkhdr script para comprobar que los encabezados son independientes. Aunque el shebang dice ‘Korn shell’, el código está realmente bien con Bash o incluso con el Bourne Shell original (System V-ish).

#!/bin/ksh
#
# @(#)$Id: chkhdr.sh,v 1.2 2010/04/24 16:52:59 jleffler Exp $
#
# Check whether a header can be compiled standalone

tmp=chkhdr-$$
trap 'rm -f $tmp.?; exit 1' 0 1 2 3 13 15

cat >$tmp.c <[email protected]"
do
    case "$file" in
    (-*)    options="$options $file";;
    (*)     echo "$file:"
            gcc $options -DHEADER=""$file"" -c $tmp.c
            ;;
    esac
done

rm -f $tmp.?
trap 0

Sucede que nunca he necesitado pasar ninguna opción que contenga espacios al script, por lo que el código no es correcto en su manejo de las opciones de espacios. Manejarlos en el shell Bourne / Korn al menos hace que el script sea más complejo sin ningún beneficio; usando Bash y un array podría ser mejor.

Uso:

chkhdr -Wstrict-prototypes -DULTRA_TURBO -I$PROJECT/include header1.h header2.h

Estándar GSFC disponible a través de Internet Archive

La URL vinculada anteriormente ya no es funcional (404). Puede encontrar el estándar C ++ (582-2003-004) en EverySpec.com (en la página 2); el estándar C (582-2000-005) parece faltar en acción.

Sin embargo, se puede acceder al estándar de codificación C de la NASA al que se hace referencia y descargarlo a través del archivo de Internet:

http://web.archive.org/web/20090412090730/http://software.gsfc.nasa.gov/assetsbytype.cfm?TypeAsset=Standard

Ver también:

  • Debo usar #include en encabezados?
  • ¿Cómo vincular varios archivos de implementación en C?
  • Profesional #include ¿contenido?
  • ¿Dónde documentar funciones en C o C ++?

Asegúrese de incluir todo lo que necesita en el encabezado, en lugar de asumir que algo que incluyó incluye algo más que necesita.

Comentarios y calificaciones

Si conservas algún titubeo o disposición de innovar nuestro artículo puedes realizar una acotación y con gusto lo estudiaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *