420 likes | 563 Views
Archivos de Encabezamiento (Header Files). Informática II Prof. Dr. Gustavo Patiño MJ 16- 18 28-01-2014. Diseño de programas grandes.
E N D
Archivos de Encabezamiento(Header Files) Informática II Prof. Dr. Gustavo Patiño MJ 16- 18 28-01-2014
Diseño de programas grandes • Aquellos programas con un gran número de lineas, como por ejemplo su proyecto del funcionamiento de un celular, deben ser divididos en archivos pequeños para efectos de facil modificación, rápida identificación de errores, compilación rápida y reutilización en otros programas, aplicaciones o proyectos. • Separación de Interfaz e Implementación
Separación de código (2) • Cada pareja de archivos de interfaz y su implementación debe contener una colección coherente de funciones relacionadas, como pro ejemplo, • el código para dibujar el tablero de un juego, • el código para la contabilidad de un almacen, • el código para el control de un motor, • y asi sucesivamente.
Separación de código (3) • Un sólo archivo, por ejemplo el main.c/main.cpp deberá definir el main(), y en el cual deben ser llamadas las funciones definidas en los otros archivos.
Separación de Interfaz e Implementación • Separación de interfaz e implementación en distintos archivos: • Ventaja: • Hace más fácil la modificación de programas: Los cambios en la implementación de una clase no afectan al programa que las usa, siempre que no cambie la interfaz. • Desventaja: • Archivos de encabezado • Contienen alguna parte de la implementación • Funciones miembro inline • Sugerencias sobre otras partes de la implementación • Miembros private
Separación de Interfaz e Implementación (2) • Archivos de encabezado (HeaderFile) • Definiciones de clases y prototipos de funciones. • Todos los typedef's, enum's, struct's. • Se incluye en todos los archivos que utilicen la clase y las funciones declaradas. • #include • Extensión de fichero .h • Ficheros con código fuente • Definición de funciones miembro. • Todos los prototiposque son “private”, estoes, que no son utilizadosporotrosarchivos. • Convención: Códigos fuente con mismo nombre base • Se compila y se enlaza con el archivo que contiene el programa principal
Estructura de los Header File #ifndef CODE_NAME #define CODE_NAME …structs, classes, enums, prototypes… #endif • Las instrucciones #ifndef/#define/#endif son una regla standard que garantiza que este archivo .h sea cargado máximo una sola vez, sin importar cuantos archivos lo incluyan como un #include.
Ejemplo de un Header File #ifndef FISH_H #define FISH_H typedef struct { int type, dir; double x_pos, y_pos, size, speed; unsigned long color; } OBJECT; void DrawFish(OBJECT *pFish); void DrawFood(OBJECT *pFood); void MoveFish(OBJECT *pFish); void MoveFood(OBJECT *pFood); #endif
Usandosus Header (.h) Files • Use #include "…"para incluir un archivo de encabezamiento definido por usted. • Ejemplo: #include “time.h" • Coloque sus archivos de encabezamiento en la misma carpeta que sus archivos C/C++. • Use #include <…> para incluir los archivos de encabezamiento standard de C/C++. • Ejemplo: #include <string>
Usandosus Header (.h) Files (2) • Coloque sus archivos de código .c en la misma carpeta que los otros archivos de su proyecto. • No incluya archivos con definición de códigos, esto es, no escriba en ningún archivo #include “time.c".
1 // Fig. 6.5: time1.h 2 // Declaración de la clase Time. 3 // Las funciones miembro están definidas en time1.cpp 4 5 // Previene múltiples inclusiones del fichero de encabezado 6 #ifndefTIME1_H 7 #defineTIME1_H 8 9 // Definición del tipo abstracto de datos Time 10 class Time { 11 12 public: 13 Time(); // constructor 14 void setTime( int, int, int ); // fija hora, minuto, segundo 15 void printUniversal(); // imprime hora en formato universal 16 void printStandard(); // imprime hora en formato estándar 17 18 private: 19 int hora; // 0 - 23 (formato de reloj de 24-horas) 20 int minuto; // 0 - 59 21 int segundo; // 0 - 59 22 23 }; // fin de la clase Time 24 25 #endif time1.h “Si no está definido” La directiva del procesador define el nombre TIME1_H. Convención de nombre: nombre de fichero de encabezado con subrayado sustituyendo al punto. El código entre las directivas #ifndef y #endif no se incluye si el nombre TIME1_H ya está definido.
1 // Fig. 6.6: time1.cpp 2 // Definición de funciones miembro para la clase Time. 3 #include <iostream> 4 #include <iomanip> 5 usingstd::cout; 6 usingstd::setfill; 7 usingstd::setw; 8 // incluye definición de clase Time en time1.h 9 #include"time1.h" 10 11 // El constructor Time inicializa cada dato miembro a cero. 12 // Asegura que todos los objetos Time se inicien en estado consistente. 13 Time::Time() 14 { 15 hora = minuto = segundo = 0; 16 } // fin de constructor Time 17 18 // Escribe nuevo valor de Time usando hora universal. Comprueba la 19 // validez de los datos. Fija los datos no válidos a cero. 20 void Time::setTime( int h, int m, int s ) 21 { 22 hora = ( h >= 0 && h < 24 ) ? h : 0; 23 minuto = ( m >= 0 && m < 60 ) ? m : 0; 24 segundo = ( s >= 0 && s < 60 ) ? s : 0; 25 } // fin de función setTime 26 time1.cpp(1 de 2) Incluye el fichero de encabezado time1.h. Nombre del fichero de encabezado entre comillas; ponerlo entre ángulos causa que el preprocesador asuma que el encabezado es parte de la Biblioteca Estándar de C++.
27 // imprime Time en formato universal 28 void Time::imprimeUniversal() 29 { 30 cout << setfill( '0' ) << setw( 2 ) << hora << ":" 31 << setw( 2 ) << minuto << ":" 32 << setw( 2 ) << segundo; 33 } // fin de la función imprimeUniversal 34 35 // imprime Time en formato estándar 36 void Time::imprimeEstandar() 37 { 38 cout << ( ( hora == 0 || hora == 12 ) ? 12 : hora % 12 ) 39 << ":" << setfill( '0' ) << setw( 2 ) << minuto 40 << ":" << setw( 2 ) << segundo 41 << ( hora < 12 ? " AM" : " PM" ); 42 } // fin de función imprimeEstandar time1.cpp(2 de 2)
1 // Fig. 6.7: fig06_07.cpp 2 // Programa para comprobar la clase Time. 3 // NOTA: Este fichero debe compilarse con time1.cpp. 4 #include <iostream> 5 using std::cout; 6 using std::endl; 7 // incluye definición de clase Time en time1.h 8 #include"time1.h" 9 10 int main() 11 { 12 Time t; // instancia el objeto t de la clase Time 13 14 // imprime valores iniciales del objeto Time t 15 cout << "La hora universal inicial es "; 16 t.imprimeUniversal(); // 00:00:00 17 cout << "\nLa hora estándar inicial es "; 18 t.imprimeEstandar(); // 12:00:00 AM 19 20 t.setTime( 13, 27, 6 ); // cambio la hora 21 // imprimo los nuevos valores del objeto Time t 22 cout << "\n\nLa hora universal después de setTime es "; 23 t.imprimeUniversal(); // 13:27:06 24 cout << "\nLa hora estándar después de setTime es "; 25 t.imprimeEstandar(); // 1:27:06 PM 26 fig06_07.cpp(1 de 2) Incluye fichero de encabezado time1.h para asegurar una correcta creación/manipulación y determinar el tamaño del objeto de la clase Time.
27 t.setTime( 99, 99, 99 ); // intenta valores no válidos 28 29 // imprimo valores de t después de especificar valores no válidos 30 cout << "\n\nDespués de intentar establecer valores no válidos:" 31 << "\nHora universal: "; 32 t.imprimeUniversal(); // 00:00:00 33 cout << "\nHora estándar: "; 34 t.imprimeStandard(); // 12:00:00 AM 35 cout << endl; 36 37 return0; 38 } fig06_07.cpp(2 de 2) Compilación: co fig06_07 time1 g++ -o fig06_07.exe fig06_07.cpp time1.cpp La hora universal inicial es 00:00:00 La hora estándar inicial es 12:00:00 AM La hora universal después de setTime es 13:27:06 La hora estándar después de setTime es 1:27:06 PM Después de intentar establecer valores no válidos: Hora universal: 00:00:00 Hora estándar: 12:00:00 AM fig06_07.cpp salida
Funciones de acceso y de utilidades • Funciones de acceso • public • Leen/visualizan datos • Funciones de predicado • Chequean condiciones verdadera/falsa • Funciones de utilidades (funciones de ayuda) • private • Dan apoyo a la operación de las funciones miembro public de la clase • No están hechas para que los clientes de una clase las utilicen directamente
1 // Fig. 6.9: salesp.h 2 // Definición de clase SalesPerson. 3 // Funciones miembro definidas en salesp.cpp. 4 #ifndefSALESP_H 5 #defineSALESP_H 6 7 class SalesPerson { 8 9 public: 10 SalesPerson(); // constructor 11 void getSalesFromUser(); // obtiene ventas del teclado 12 void setSales( int, double ); // fija ventas de un mes 13 void printAnnualSales(); // suma e imprime ventas 14 15 private: 16 double totalAnnualSales(); // función de utilidad 17 double sales[ 12 ]; // ventas de 12 meses 18 19 }; // fin de la clase SalesPerson 20 21 #endif salesp.h Función de acceso set realiza validación de datos. Función de utilidad private.
1 // Fig. 6.10: salesp.cpp 2 // Funciones miembro de la clase SalesPerson. 3 #include <iostream> 4 #include <iomanip> 5 using std::cout; 6 using std::cin; 7 using std::endl; 8 using std::fixed; 9 using std::setprecision; 10 // incluye la definición de la clase SalesPerson en salesp.h 11 #include"salesp.h" 12 13 // inicializa elementos del array de ventas sales a 0.0 14 SalesPerson::SalesPerson() 15 { 16 for ( int i = 0; i < 12; i++ ) 17 sales[ i ] = 0.0; 18 } // fin del constructor SalesPerson 19 20 // Obtiene 12 cifras de ventas del usuario por teclado 21 void SalesPerson::getSalesFromUser() 22 { 23 double salesFigure; 24 for ( int i = 1; i <= 12; i++ ) { 25 cout << "Introduzca las ventas del mes " << i << ": "; 26 cin >> salesFigure; 27 setSales( i, salesFigure ); 28 } // fin de for 29 } // fin de función getSalesFromUser 30 salesp.cpp(1 de 2)
31 // Función para fijar una de las 12 cifras de ventas mensuales; la función 32 // resta 1 del valor del mes para obtener un índice correcto en array sales 33 voidSalesPerson::setSales( int mes, double cantidad ) 34 { 35 // comprueba mes y cantidad con valores correctos 36 if ( mes >= 1 && mes <= 12 && cantidad > 0 ) 37 sales[ mes - 1 ] = cantidad; // ajuste para índices 0-11 38 else// mes o ventas no válidas 39 cout << "Mes o cifra de ventas no válidos" << endl; 40 } // fin de función setSales 41 42 // imprime el total de las ventas del año (con ayuda de función de utilidad) 43 voidSalesPerson::printAnnualSales() 44 { 45 cout << setprecision( 2 ) << setiosflags(ios::fixed) 46 << "\nEl total anual de ventas es: $" 47 << totalAnnualSales() << endl; // llamo a función de utilidad 48 } // fin de función printAnnualSales 49 50 // Función de utilidad private para calcular el total de ventas 51 doubleSalesPerson::totalAnnualSales() 52 { 53 double total = 0.0; // inicializa total 54 for ( int i = 0; i < 12; i++ ) // suma ventas de 12 meses 55 total += sales[ i ]; 69 return total; 71 } // fin de función totalAnnualSales salesp.cpp(2 de 2) Función de acceso set realiza chequeo de validez. Función de utilidad private para ayudar a la función printAnnualSales; encapsula la lógica de manipulación del array sales.
1 // Fig. 6.11: fig06_11.cpp 2 // Demostración de la función utilidad. 3 // Compila este programa con salesp.cpp 4 // incluye la definición de la clase SalesPerson de salesp.h 5 #include"salesp.h" 6 7 int main() 8 { 9 SalesPerson s; // crea un objeto SalesPerson s 10 s.getSalesFromUser(); // código secuencial simple; no 11 s.printAnnualSales(); // estructuras de control en main 12 return0; 13 } fig06_11.cpp Secuencia simple de llamadas a funciones miembro; lógica encapsulada en funciones miembro. Introduzca las ventas del mes 1: 5314.76 Introduzca las ventas del mes 2: 4292.38 Introduzca las ventas del mes 3: 4589.83 Introduzca las ventas del mes 4: 5534.03 Introduzca las ventas del mes 5: 4376.34 Introduzca las ventas del mes 6: 5698.45 Introduzca las ventas del mes 7: 4439.22 Introduzca las ventas del mes 8: 5893.57 Introduzca las ventas del mes 9: 4909.67 Introduzca las ventas del mes 10: 5123.45 Introduzca las ventas del mes 11: 4024.97 Introduzca las ventas del mes 12: 5923.92 El total anual de ventas es: $60120.59 fig06_11.cppsalida
Proceso de Compilación: Make • 1. Introducción • Make es una utilidad que permite definir reglas de dependencia entre ficheros. Aunque puede utilizarse para diferentes fines, está especialmente orientado a la compilación de código. • El propósito de make es determinar automáticamente qué piezas de un programa necesitan ser recompiladas y lanzar las órdenes necesarias para lograrlo.
Makefiles • Para utilizar make debe escribirse normalmente un fichero llamado GNUmakefile, makefile o Makefile (se aconseja esta última forma) que describe las relaciones de dependencia de los ficheros que forman un programa. • En un programa normalmente el fichero ejecutable se genera a partir de ficheros objeto, los cuales a su vez se construyen mediante la compilación de los ficheros fuente. El fichero makefile contiene esencialmente variables y reglas.
MakefilesComentarios • Para escribir comentarios debe insertarse el carácter # al comienzo del texto en cuestión. Se pueden añadir al final de una lista de dependencias o de una orden. Si aparecen solos en una línea, deben comenzar en la primera columna.
MakefilesInformación al usuario • Es posible imprimir texto en la consola como complemento de información para el usuario. Para ello se utiliza la orden echo. Esta orden debe utilizarse en una regla como cualquier otra orden
MakefilesVariables • Una variable es un nombre simbólico que será substituido por su valor en el momento de la aplicación de las reglas posteriores. • Para definir una variable se utiliza la siguiente sintaxis: • <IDENTIFICADOR>=valor Un ejemplo: • NOMBRE_PROGRAMA = uniq
MakefilesVariables (2) • Por convenio las variables tienen identificadores con todas las letras en mayúscula. • Para "expandir" una variable, es decir, para obtener su valor se utiliza la siguiente sintaxis: • $(IDENTIFICADOR)
VariablesfrecuentesdelMakefile • Make define algunas variables que es necesario conocer y que ya contienen valores por defecto. Algunas de ellas son: • AR:Programa de empaquetado. Por defecto es ar. • CC:Compilador de C. Por defecto es cc. • CXX: Compilador de C++. Por defecto es g++. • CPP:Preprocesador de C. • CFLAGS:Opciones de compilación C. • CXXFLAGS:Opciones de compilación C++. • CPPFLAGS:Opciones para el preprocesador. • LDFLAGS:Opciones para el montador (enlazador). • LDLIBS:Librerías a utilizar en el montaje.
MakefileReglas • La sintaxis de una regla es: • <objetivo>: <requisitos> <orden para generar objetivo a partir de requisitos> • Tanto <objetivo> como <requisitos> suelen ser nombres de ficheros.
MakefileReglas (2) • Cuando make evalúa una regla debe poder ejecutar la orden asociada para generar el objetivo a partir de los requisitos. • Si falta alguno de los archivos requisito, make buscará una regla que le permita saber cómo generarlo; si no existe tal regla terminará informando del error.
MakefileReglas (3) • <objetivo>: <requisitos> <orden para generar objetivo a partir de requisitos> • El nombre del objetivo debe comenzar en la primera columna y debe estar seguido del carácter dos puntos (:) y al menos un espacio. • A continuación se enumeran los ficheros requeridos (llamados dependencias).
MakefileReglas (4) • En la siguiente línea se describe la orden que ha de generar el objetivo. • Dicha línea debe comenzar obligatoriamente con un carácter TABULACIÓN (TAB), en caso contrario make informará de un error de sintáxis. • Cada regla puede contener varias líneas de órdenes que seguirán el mismo formato. • Cada regla debe ir separada de la anterior por medio de una línea en blanco y al final del archivo también debe aparecer una línea vacía.
MakefileExplicacióndelejemplo • En el ejemplo se pretende construir la aplicación hola que consta de los módulos hola.o y auxhola.o. • Cuando se ejecuta sin parámetros, make siempre empieza evaluando la primera regla que aparece en el fichero, en este caso la regla hola. • Si alguno de los dos fichero objeto no está en el directorio, make ejecutará la regla correspondiente que permite generarlo.
MakefileExplicacióndelejemplo (2) • Una característica muy importante de make es que antes de ejecutar una regla comprueba que realmente sea necesario. • Por medio de las marcas de tiempo que el sistema operativo almacena en los descriptores de fichero, make averigua que órdenes necesita ejecutar. • Siempre que el fichero objetivo tenga una fecha más reciente que cualquiera de los ficheros requisito, la regla se evaluará pero no se ejecuta la orden. • Esto permite que cuando trabajamos con grandes proyectos formados por muchos módulos ahorremos mucho tiempo ya que make sólo recompila los ficheros necesarios para obtener la versión actualizada del ejecutable.
MakefileExplicacióndelejemplo(3) • En el ejemplo aparece una regla adicional llamada clean; esta regla elimina todos los ficheros objeto y binarios dejando sólo los fuentes. • Por convenio se la suele denominar clean aunque no es obligatorio. • También suele definirse una regla all que provoca que se evaluen todas las demás reglas de construcción. • Para ejecutar una regla en concreto debe indicarsele a make del siguiente modo. • $ makeclean
MakefileVariables automáticas • Se pueden utilizar algunos indicadores especiales que permiten hacer ficheros makefile más simples:
Ejemplo 2: Compilación de um programa dividido em varias subprogramas