Diferencia entre revisiones de «Archivo de cabecera»

Contenido eliminado Contenido añadido
m Revertidos los cambios de 190.172.148.72 (disc.) a la última edición de MaSt
Línea 5:
La ''[[biblioteca estándar de C]]'' y la ''[[biblioteca estándar de C++]]'' tradicionalmente declaran sus funciones estándar en ''header files''.
 
== Motivación ==
la cabecera es lo que llevamos en nuestra cabeso ocea cerebro bueno queria aclarar que me encanta justin bieber y muchos mas besos anonimom
En la mayoría de lenguajes de programación modernos, los programadores pueden dividir los [[programa (informática)|programas]] en componentes de menor tamaño (como pueden ser [[clase (informática)|clases]] y [[subrutina]]s) y distribuir esos componentes entre muchas unidades por traducir (típicamente en forma de [[archivo (informática)|archivos]]), que el sistema puede [[compilar]] de forma autónoma. Si una subrutina se tiene que usar al margen de la unidad por traducir donde ha sido definida, se tiene que introducir el concepto de declaración directa o [[prototipo de función|prototipos de funciones]]. Por ejemplo, una función definida así en un archivo fuente:
l vida cotidiana de mucs personas cominesa con la niñes y la dolecencia bueo me voy agradeciendo a esta paga
<source lang="c">
int add(int a, int b)
{
return a + b;
}
</source>
puede declararse (con un prototipo de función) y ser referida desde un segundo archivo fuente como sigue:
<source lang="c">
int add(int, int);
int triple(int x)
{
return add(x, add(x, x));
}
</source>
 
Sin embargo en esta simple ilustración se requiere que el programador mantenga la declaración de la función de <code>add</code> en dos sitios &nbsp;— en el archivo que contiene su implementación y en el archivo que usa la funcionalidad. Si la definición de la función llega a alterarse, entonces el programador debe actualizar todos los prototipos repartidos a lo largo del programa. Esto es necesario porque la implementación de ambos, C y C++ han de diagnosticar todas las violaciones de lo que en C++ se llama "[[one definition rule]]" (ODR), al español "regla de una única definición". De hecho, la mayoría de ellos se sirven de un [[enlazador]] para realizar esta labor. El enlazador, sin embargo, suele conocer, de forma muy limitada los tipos usados en los programas. Por ello, algunas de las violaciones de ODR no se detectan a la hora de implementar el lenguaje. Como resultado, es responsabilidad del programador el mantener la coherencia de todas las declaraciones que cruzan las fronteras de una unidad por traducir. Buscar todas estas declaraciones de una entidad externa y verficar que son compatibles de forma manual es una tarea ardua. (Nótese que C no define el término "one definition rule"&nbsp;— es específico del lenguaje C++. Si declaraciones de la misma entidad en muchos archivos fuentes de C son diferentes, la función no funcionará de forma adecuada y puede llegarse a un [[comportamiento impredecible]], independientemente de la regla que se esté violando.)
 
Para entender una violación ODR, considérese el siguiente código (correcto):
<source lang="c">
/* File print-heading.c */
#include <stdio.h>
void print_heading(void)
{
printf("standard heading\n");
}
</source>
 
<source lang="c">
/* File main.c */
void print_heading(void);
int main(void)
{
print_heading();
return 0;
}
</source>
 
La unidad por traducir representada por el archivo fuente <code>main.c</code> referencia a la función <code>print_heading()</code> que está definida en otra unidad por traducir (<code>print-heading.c</code>). De acuerdo con las reglas de [[C99]], los programadores deben declarar una función externa antes del primer uso. Para cumplir con este requisito el archivo <code>main.c</code> declara la función en la primera línea. Esta versión del código funciona de forma correcta.
 
Posteriormente, el programador que mantiene el archivo fuente <code>print-heading.c</code> puede decidir hacer la función más flexible y dar soporte a cabeceras a gusto del usuario. Una posible implementación podría ser la siguiente:
 
<source lang="c">
/* File print-heading.c */
#include <stdio.h>
void print_heading(const char *heading)
{
printf("%s\n", heading);
}
</source>
 
Si el programador olvida actualizar la declaración en <code>main.c</code>, se pueden dar resultados devastadores. La función <code>print_heading()</code> espera un argumento y hace uso del valor del mismo, sin embargo la función <code>main()</code> no provee ningún valor. Al ejecutar este programa se produce un comportamiento impredecible: la aplicación puede imprimir basura, terminar de forma inesperada o dar pie a resultados impredecibles en la plataforma en la que es ejecutado.
 
¿Por qué se puede compilar y enlazar este código sin problema alguno? El motivo es que el compilador se guía por la declaración en <code>main.c</code> a la hora de compilar la unidad por traducir <code>main.c</code>. Y esa declaración se ajusta con la forma de la función. Más tarde, cuando el enlazador combina las translation unitos ya compiladas <code>main.c</code> y <code>print-heading.c</code> (en la mayoría de implementaciones representadas como archivos <code>main.o</code> o <code>main.obj</code>), probablmente podría detectar la inconsistencia &nbsp;— pero no en C. Las implementaciones en C referencian las funciones por el nombre al nivel de archivo objeto y archivo binario, esto no incluye el valor de retorno o la lista de argumentos. El enlazador encuentra una referencia a <code>print_heading()</code> en <code>main.o</code> y una función adecuada en <code>print-heading.o</code>. Llegado este punto, toda la información relativa a tipos de argumentos de funciones se pierde.
 
¿Cómo es entonces posible llevar a cabo declaraciones múltiples sin problema alguno? La solución se llama ''header file''. El ''header file'' de un módulo declara cada función, objeto y tipo de dato que forma parte del ''interfaz público'' del módulo&nbsp;— por ejemplo, en este caso el ''header file'' incluiría sólo la delcaración de <code>add</code>. Todo aquel archivo fuente que se refiera a <code>add</code> usa la directiva <code>#include</code> en el ''header file'':
 
<source lang="c">
/* File add.h */
#ifndef ADD_H
#define ADD_H
int add(int, int);
#endif /* ADD_H */
</source>
 
(Nótese que el ''header file'' utiliza un "[[Include guard]]".)
 
<source lang="c">
/* File triple.c */
#include "add.h"
int triple(int x)
{
return add(x, add(x, x));
}
</source>
 
This reduces the [[software maintenance|maintenance]] burden: when a definition changes, only a single copy of the declaration must be updated (the one in the header file). The header file may also be included in the source file that contains the corresponding definitions, giving the compiler an opportunity to check the declaration and the definition for consistency.
 
<source lang="c">
/* File add.c */
#include "add.h"
int add(int a, int b)
{
return a + b;
}
</source>
 
Normalmente, los programadores sólo utilizan los ''header files'' para especificar los [[interfaz|interfaces]], y suelen aportar al menos, una pequeña cantidad de información explicando cómo usar los componentes declarados en el archivo. Al igual que en este ejemplo, las implementaciones de subrutinas permanecen en un archivo fuente separado, que continua siendo compilado de forma independiente. (Una excepción común entre C y C++ son las "[[función inline|funciones inline]]", que suelen incluirse en ''header files'' porque la mayoría de implementaciones no pueden expendir funciones ''inline'' de forma adecuada sin ver sus definiciones durante el [[tiempo de compilación]].)
 
== Alternativas ==