Foros del Web » Programación para mayores de 30 ;) » Programación General »

duda con el compilador GCC

Estas en el tema de duda con el compilador GCC en el foro de Programación General en Foros del Web. Holas.. tengo una duda con el compilador gcc, que es la siguiente: si tengo : -fichero.h: declaro las variables a usar en fichero1.c, ficehro2.c,fichero3.c -fichero1.c ...
  #1 (permalink)  
Antiguo 14/07/2003, 06:21
Avatar de kapachov  
Fecha de Ingreso: diciembre-2002
Ubicación: Loeches
Mensajes: 464
Antigüedad: 21 años, 4 meses
Puntos: 0
duda con el compilador GCC

Holas..

tengo una duda con el compilador gcc,
que es la siguiente:

si tengo :

-fichero.h: declaro las variables a usar en fichero1.c, ficehro2.c,fichero3.c
-fichero1.c que lo que hace es pedir el nombre
-fichero2.c que lo que hace es pedir el apellido
-fichero3.c iprime la info pedida por fichero1 y fichero2.c

en cada uno de estos *.c incluyo el fichero.h,
como hace para darse cuenta y no sacar un error de redeclaracion de variables?

__________________
Siempre hago lo que quiero...
Aunque no quiera...
  #2 (permalink)  
Antiguo 14/07/2003, 12:27
Ex Colaborador
 
Fecha de Ingreso: junio-2002
Mensajes: 9.091
Antigüedad: 21 años, 10 meses
Puntos: 16
Hola,

Esa es una duda de C, no de gcc.

Si no recuerdo mal, lo que se hacia era declarar la variable con extern en el .h y luego declararla normal (como global) en uno solo de los .c. Seria algo asi:

- fichero.h

extern int variable;

- fichero1.c

#include "fichero.h"

int variable;

- fichero2.c

#include "fichero.h"

- fichero3.c

#include "fichero.h"

Espero haber sido de ayuda.
__________________
Josemi

Aprendiz de mucho, maestro de poco.
  #3 (permalink)  
Antiguo 14/07/2003, 18:31
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola. Nuestro amigo josemi tiene razón en parte respecto al uso de variables extern. Básicamente, si tienes una variable que quieres compartir entre varios archivos .c, puedes definirla en algún archivo de ellos (generalmente aquel que contenga la función main()), y luego declarar esa misma variable usando la palabra clave extern en todos los demás archivos que usen esa variable.

Ahora bien, me parece a mí que te refieres a un tipo de situaciones sutilmente distintas. Tienes un archivo de cabeceras (.h) en donde tienes todo tipo de maravillas que usarás en varios archivos distintos (pueden ser prototipos, declaración de variables, enumeraciones, estructuras, etc.).

Si no te entiendo mal, tu curiosidad te ha llevado a hacerte la (muy buena) pregunta, ¿cómo hace el compilador para no redefinir las cosas si las incluye más de una vez? ¿tendré que hacer las inclusiones en un orden especial? Bueno, al menos esas preguntas me asaltaron a mí hace algún tiempo.

En ese caso, te cuento que hay un truco muy popular, y que muy posiblemente ya hayas visto en la práctica si has tenido la oportunidad de estudiar el código fuente de alguna aplicación seria. Incluso tengo entendido que herramientas de generación de código como las que vienen con el compilador de C++ de microsoft las implementan de forma natural.

El truco es simple: al comienzo del archivo de cabecera, digamos por ejemplo que tenemos uno que se llame maravillas.h, se coloca algo similar a esto:

Código:
#ifndef __MARAVILLAS_H
#define __MARAVILLAS_H
Después de estas líneas viene todo el contenido normal de tu archivo. Finalmente, justo después de tus últimas líneas de código, se cierra la directiva #ifndef:

Código:
#endif  /* __MARAVILLAS_H */
¿Ves cómo funciona el truco? Es simple y astuto, a decir verdad. El compilador tomará tus archivos de código fuente (sin importar el orden) y va incluyendo los archivos de cabecera en la medida en que se necesiten. En este ejemplo, la primera vez que maravillas.h sea incluido, la directiva #ifndef revisará si se ha definido previamente una macro con el nombre __MARAVILLAS_H, y por supuesto no la encentrará (a menos que la hayas definido en otra parte, por supuesto... por eso suele utilizarse la convención de usar el nombre del archivo con "underlines" al comienzo como nombre de la macro), así que ejecuta el código que encuentra a continuación, que de entrada empieza por definir la macro que acaba de revisar.

De este modo, en futuras inclusiones del archivo, la directiva #ifndef toma un rumbo diferente (ignorando el contenido del archivo). Como el final de la directiva condicional está al final del archivo, lo que se logra en la práctica es proteger el contenido completo del archivo para que no sea incluido y procesado más de una vez.

También es curioso que menciones esto como una duda sobre gcc. De hecho, este tipo de prácticas es tan común (o estándar, dicen los libros), que el pre-procesador de gcc lo reconoce y nisiquiera trata de acceder aquellos archivos que definen su "símbolo de protección". Realmente útil. Es muy bonito trabajar con gcc.

Un cordial saludo.
  #4 (permalink)  
Antiguo 15/07/2003, 04:20
Avatar de kapachov  
Fecha de Ingreso: diciembre-2002
Ubicación: Loeches
Mensajes: 464
Antigüedad: 21 años, 4 meses
Puntos: 0
holas gracias a los 2 por sus respuestas...

Cita:
Si no te entiendo mal, tu curiosidad te ha llevado a hacerte la (muy buena) pregunta, ¿cómo hace el compilador para no redefinir las cosas si las incluye más de una vez? ¿tendré que hacer las inclusiones en un orden especial? Bueno, al menos esas preguntas me asaltaron a mí hace algún tiempo.
hasta aqui vamos bien... es lo que necesito..



Cita:
El truco es simple: al comienzo del archivo de cabecera, digamos por ejemplo que tenemos uno que se llame maravillas.h, se coloca algo similar a esto:

code:
#ifndef __MARAVILLAS_H
#define __MARAVILLAS_H



Después de estas líneas viene todo el contenido normal de tu archivo. Finalmente, justo después de tus últimas líneas de código, se cierra la directiva #ifndef:

code:
#endif /* __MARAVILLAS_H */

pero si no utilizo esto, como es el caso mio..
no me esta sacando problemas de redeclaracion, por que?



Cita:
También es curioso que menciones esto como una duda sobre gcc. De hecho, este tipo de prácticas es tan común (o estándar, dicen los libros), que el pre-procesador de gcc lo reconoce y nisiquiera trata de acceder aquellos archivos que definen su "símbolo de protección". Realmente útil. Es muy bonito trabajar con gcc.
el gcc lo reconoce pero si esta con las directivas :

#ifndef __MARAVILLAS_H
#define __MARAVILLAS_H
#endif /* __MARAVILLAS_H */


bueno espero me puedan entender y seguir ayudando, por que sigo con la duda...
__________________
Siempre hago lo que quiero...
Aunque no quiera...
  #5 (permalink)  
Antiguo 15/07/2003, 05:18
Ex Colaborador
 
Fecha de Ingreso: junio-2002
Mensajes: 9.091
Antigüedad: 21 años, 10 meses
Puntos: 16
Bueno, son dos cosas distintas (a mi entender). Lo de extern es para que a la hora de linkar los objetos no de error de redeclaracion. Lo de #ifdef es para evitar la inclusion repetida de codigo por culpa de includes anidados o equivocaciones del programador, y esta inclusion da error de compilacion. Se debe usar las dos, ya que son errores distintos.

No se si lo he explicado claramente.

Saludos.
__________________
Josemi

Aprendiz de mucho, maestro de poco.
  #6 (permalink)  
Antiguo 15/07/2003, 07:57
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola de nuevo.

En tu caso, creo que habría que estudiar más detalladamente el código con el que estás trabajando. Quizás se trate de algo que no resulte tan obvio. Quizás gcc no considera como error fatal la situación que mencionas, pero podrías ver mensajes de advertencia si le pasas algunas banderas apropiadas.. no lo sé con certeza.

¿Podrías enviar el código en cuestión que te tiene con esa duda? Sería interesante llegar al corazón del asunto... todos los días se aprende algo, creo yo.
  #7 (permalink)  
Antiguo 15/07/2003, 09:30
Avatar de kapachov  
Fecha de Ingreso: diciembre-2002
Ubicación: Loeches
Mensajes: 464
Antigüedad: 21 años, 4 meses
Puntos: 0
Holas a los 2, gracias otra vez por su colaboracion y paciencia...


/*prueba.h*/

prueba();
pruebb();
pruebc();

char nombre[40],edad[3];

////////////////////////////////////////////////////

/*prueba.c*/

#include "/home/developer/gcc-pruebas/prueba.h"

prueba ()
{
printf ("\nDIGITE SU NOMBRE:");
scanf ("%s",nombre);
}

////////////////////////////////////////////////////

/*pruebb.c*/

#include "/home/developer/gcc-pruebas/prueba.h"

pruebb ()
{
printf ("\nDIGITE SU EDAD:");
scanf ("%s",edad);
}

////////////////////////////////////////////////////

/*pruebc.c*/

#include "/home/developer/gcc-pruebas/prueba.h"

pruebc ()
{
printf ("\nNOMBRE\t\t\tEDAD\n");
printf ("%s\t\t\t%s",nombre,edad);
}


////////////////////////////////////////////////////

orden de compilacion

#gcc -Wall -o exe prueba.c pruebb.c pruebc.c principal.c


la version de gcc que uso es la 2.96

PD: les pido el favor no copiar mi codigo fuente! lo tengo patentado
__________________
Siempre hago lo que quiero...
Aunque no quiera...
  #8 (permalink)  
Antiguo 15/07/2003, 11:14
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Creo que ya veo más claramente la naturaleza de la situación. Pienso que lo que sucede es que, efectivamente, tu programa no está haciendo nada inválido, ni amerita warning alguno, una vez se corrigen ciertos detalles.

En realidad, declarar variables en archivos de cabecera es perfectamente legal en ANSI C y, aunque suele ser considerado como un recurso poco elegante y evitado al máximo por mucho programadores, constituye un medio válido de solucionar un problema de programación. Es común en ciertas aplicaciones colocar declaraciones de variables globales en archivos de cabecera, los cuales serán incluidos desde varios archivos fuente.

Quizás tu confusión proviene de la sutil pero fundamental diferencia de una declaración y una definición. La definición es el lugar en donde una variable es creada (y se reserva el espacio de memoria necesario para almacenar los valores de la variable). La declaración es el lugar en donde la naturaleza (el tipo) de una variable se declara, pero no se reserva memoria aun. Las variables pueden ser declaradas varias veces, pero definidas sólo una.

He modificado un poco tu código, y de este modo verás que pasa la etapa de compilación de gcc sin warnings:

Código:
/* principal.c */

#include "prueba.h"

int
main (void)
{
	prueba();
	pruebb();
	pruebc();

	return 0;
}

/* fin principal.c */



/* pruebab.c */

#include "prueba.h"

void
pruebb (void)
{
	printf ("\nDIGITE SU EDAD:");
	scanf ("%s", edad);
}

/* fin pruebab.c */



/* prueba.c */

#include "prueba.h"

void
prueba (void)
{
	printf ("\nDIGITE SU NOMBRE:");
	scanf ("%s" ,nombre);
}

/* fin prueba.c */



/* pruebac.c */

#include "prueba.h"

void
pruebc (void)
{
	printf ("\nNOMBRE\t\t\tEDAD\n");
	printf ("%s\t\t\t%s", nombre, edad);
}

/* fin pruebac.c */



/* prueba.h */

#include <stdio.h>

void prueba (void);
void pruebb (void);
void pruebc (void);

char nombre[40], edad[3];

/* fin prueba.h */
Ahora bien, trata de agregar una definición en el archivo prueba.h, por ejemplo:

Código:
char no_valido[] = "Estoy definiendome...";
Lee la salida del proceso de compilarlo... ¿era eso lo que esperabas desde un comienzo?

Ahora, te diré que personalmente soy de las personas que tratan de evitar ese tipo de cosas al máximo. En realidad lo considero poco elegante, y usualmente cuando uno recurre a ese tipo de "trucos" en un programa, es porque en el fondo hay un problema más serio en el código (generalmente de diseño de los algoritmos u otras cosas de fondo). Creo que bajo ninguna circunstancia se justifica realmente el uso de variables globales; es buena idea evitarlas al máximo. Por supuesto, es sólo mi consejo personal.

Otra cosa, un poco fuera de tema... Me ha sorprendido un poco tu broma sobre tu código "patentado". En realidad cuando leo ese tipo de cosas, aun cuando sea en broma, me preocupa bastante. Te recomiendo enormemente que te informes más sobre el tema de las patentes y su relación con la creación de software. Te darás cuenta que las patentes en la industria del software hacen mucho más daño que otra cosa. Si no ha sido más que una broma y eres consciente del mal que constituyen las patentes, me alegra mucho. De otra forma, por favor considera estudiar un poco más sobre el tema, te harás un favor enorme a tí y a la gente (colegas programadores) que te rodee. Con mucho gusto yo podría colaborarte con el tema....

Que estés muy bien.
  #9 (permalink)  
Antiguo 15/07/2003, 14:55
Ex Colaborador
 
Fecha de Ingreso: junio-2002
Mensajes: 9.091
Antigüedad: 21 años, 10 meses
Puntos: 16
Hola,

Hace siglos que no programo en C, pero creo tal como dice leonardop seguiria fallando ya que estas creando 3 veces las variables, uno para cada .obj generado. En tiempo de linkado de los 3 .obj, ya no se si dara error de que redecalaracion, o que cada funcion hara referencia a uno de los 3 juegos de variables. Todo sera cuestion de probarlo con el compilador. Declarando con extern las variables en el .h y luego eclarandolas normal (global) en principal.c no deberia haber problemas.

Otra cosa, ¿prueba.h se incluye en otro fichero? Supongo que en principal.c. Porque si no, podrias pasar de poner las declaraciones (¿o era definiciones?) de las funciones en el .h, porque en los otros .c no las necesitan.

Mira, despues de enseñar el lenjuage de programacion, lo primero que te dicen es que el goto es el demonio. Y lo segundo es que las variables globales son el diablo. Huye de ambos tan rapido como puedas, o te llevaran a los infiernos de codigos imposibles de depurar.

La forma "correcta" de este programa seria:
Código:
/* principal.c */

#include "prueba.h"

int
main (void)
{
       char nombre[40], edad[3];

	prueba(nombre);
	pruebb(edad);
	pruebc(nombre,edad);

	return 0;
}

/* fin principal.c */



/* pruebab.c */

#include "prueba.h"

void
pruebb (char * edad)
{
	printf ("\nDIGITE SU EDAD:");
	scanf ("%s", edad);
}

/* fin pruebab.c */



/* prueba.c */

#include "prueba.h"

void
prueba (char * nombre)
{
	printf ("\nDIGITE SU NOMBRE:");
	scanf ("%s" ,nombre);
}

/* fin prueba.c */



/* pruebac.c */

#include "prueba.h"

void
pruebc (char *nombre,char * edad)
{
	printf ("\nNOMBRE\t\t\tEDAD\n");
	printf ("%s\t\t\t%s", nombre, edad);
}

/* fin pruebac.c */



/* prueba.h */

#include <stdio.h>

void prueba (char * nombre);
void pruebb (char * edad);
void pruebc (char * nombre,char * edad);

/* fin prueba.h */
si es que mis olvidadas neuronas de C no se equivocan con los punteros.

Como ves, no hay variables globales, se pasa todo por parametros (habria que añadir const y demas). Solo creas unas variables, locales al main() (como debe ser). Acostumbrate a programar sin variables globales, seras mas feliz, aunque al principio te parezca mas "rollo" ir pasando las variables de funcion en funcion.

Sobre las "broma" de la patente, supongo que alo que el se referia (en broma) es que lo tenia registrado en la propiedad intelectual (totalmente licito y recomendable). Como bien comenta leonardop, las patentes del software son peligrosas para los programadores (pero muy lucrativas para el dueño de la patente). ¿Sabes que si tu ahora haces un programa que lee y crea ficheros gif comprimidos (el mas normal de los formatos GIF), debes pagar al dueño de la patente de los GIF (en concreto la patente sobre el algoritmo de encriptacion)? Por esa razon las librerias y programas opensource ya no soportan el formato gif.

Saludos.

PD: Voy a ver si saco el compilador y hago un par de pruebas, aunque parece que ya las haces tu kapachov, ¿verdad?
__________________
Josemi

Aprendiz de mucho, maestro de poco.
  #10 (permalink)  
Antiguo 15/07/2003, 15:31
Avatar de Mithrandir
Colaborador
 
Fecha de Ingreso: abril-2003
Mensajes: 12.106
Antigüedad: 21 años
Puntos: 25
Sobre el GIF, si no me equivoco, salio en www.barrapunto.com que la patente sobre el GIF caducaba hace unos 5 dias, y que el dueño no la pensaba renovar.

o sea que... China libre.

Sobre lo de las patentes, si, es lamentable, aunque yo estoy en America y el problema legal esta atualmente en europa, en barrapunto y la revista TodoLinux he leido un poco sobre el tema.
__________________
"El hombre, en su orgullo, creó a Dios a su imagen y semejanza."
Friedrich Nietzsche
  #11 (permalink)  
Antiguo 16/07/2003, 07:43
Avatar de kapachov  
Fecha de Ingreso: diciembre-2002
Ubicación: Loeches
Mensajes: 464
Antigüedad: 21 años, 4 meses
Puntos: 0
gracias a los 2 de nuevo!

1º que todo lo de las patentes era mas que broma
es decir no tenia sentido!, como mi codigo era
tan basico tan tan..


leonardop wrote:

Cita:
lee la salida del proceso de compilarlo... ¿era eso lo que esperabas desde un comienzo?
eso a esto me referia...




josemi wrote:

Cita:
PD: Voy a ver si saco el compilador y hago un par de pruebas, aunque parece que ya las haces tu kapachov, ¿verdad?
con respecto a las pruebas, si las estoy haciendo yo claro que si haces alguna y pòdes mandarmela no me enojo
__________________
Siempre hago lo que quiero...
Aunque no quiera...
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 22:00.