2011-10-28 15 views
5

Por alguna razón, recibo varias declaraciones de contenido dentro de mi archivo de encabezado aunque estoy usando guardias de encabezado. Mi código de ejemplo es el siguiente:Encabezado/Incluir guardias no funcionan?

main.c:

#include "thing.h" 

int main(){ 
    printf("%d", increment()); 

    return 0; 
} 

thing.c:

#include "thing.h" 

int increment(){ 
    return something++; 
} 

thing.h:

#ifndef THING_H_ 
#define THING_H_ 

#include <stdio.h> 

int something = 0; 

int increment(); 

#endif 

Cuando intento compilar este, GCC dice que tengo múltiples definiciones de algo variable. ifndef debería asegurarse de que esto no ocurra, por lo que estoy confundido por qué es así.

+2

El * compilador * error "múltiples * declaraciones *" no es lo mismo que * linker * error "multiple * definitions *". Usted ha mencionado ambos en su pregunta (cuando de hecho el único problema es este último); entender la diferencia es clave para entender qué está yendo mal. Los protectores de encabezado evitan múltiples * declaraciones *, no múltiples * definiciones *. – Clifford

+0

@Clifford lo siento, debería haber mencionado que estaba obteniendo un error de enlazador. – user1007968

+0

Además, en C 'int increment();' no es un prototipo, pero declara una función con un número de parámetros no especificado. Use 'int increment (void);' para eso. –

Respuesta

9

Las protecciones incluidas funcionan correctamente y no son la fuente del problema.

Lo que sucede es que cada unidad de compilación que incluye thing.h obtiene su propio int something = 0, por lo que el enlazador se queja de varias definiciones.

Aquí es cómo solucionar esto:

thing.c:

#include "thing.h" 

int something = 0; 

int increment(){ 
    return something++; 
} 

thing.h:

#ifndef THING_H_ 
#define THING_H_ 

#include <stdio.h> 

extern int something; 

int increment(); 

#endif 

De esta manera, sólo se thing.c tendrá una instancia de something, y main.c se referirá a él.

+2

También podría agregar que incluso si no hubiera múltiples errores de definición, cada TU tendrá su propia copia de la variable y no lograría el propósito de compartir la misma variable en todos los archivos fuente. –

3

Tiene una definición en cada unidad de traducción (una en main.c, y una en thing.c). Los resguardos de encabezado evitan que el encabezado se incluya más de una vez en una sola unidad de traducción .

Es necesario declaransomething en el archivo de cabecera, y sólo definen en thing.c, al igual que la función:

thing.c:

#include "thing.h" 

int something = 0; 

int increment(void) 
{ 
    return something++; 
} 

thing.h:

#ifndef THING_H_ 
#define THING_H_ 

#include <stdio.h> 

extern int something; 

int increment(void); 

#endif 
4

Las protecciones del encabezado evitarán que el archivo se compi dirigido más de una vez en la misma unidad de compilación (archivo). Lo está incluyendo en main.c y thing.c, por lo que se compilará una vez en cada uno, lo que lleva a que la variable something se declare una vez en cada unidad, o dos veces en total.

1

La variable something se debe definir en un archivo .c, no en en un archivo de encabezado.

Solo las estructuras, macros y declaraciones de tipos para las variables y prototipos de funciones deben estar en archivos de encabezado. En su ejemplo, puede declarar el tipo de something como extern int something en el archivo de encabezado.Pero la definición de la variable en sí debe estar en un archivo .c.

Con lo que ha hecho, la variable something se definirá en cada archivo.c que incluye thing.h y se obtiene un mensaje de error "algo definido varias veces" cuando se trata de vincular GCC todo junto.

+0

Su primera afirmación es incorrecta. La variable debe * declararse * con la palabra clave * extern * en el archivo de encabezado y * definida * en un único archivo fuente. –

1

intentan evitar la definición global de variables. usa funciones como increment() para modificar y leer su valor en su lugar. de esa manera puede mantener la variable estática en el archivo thing.c, y está seguro de que solo las funciones de ese archivo modificarán el valor.

+0

Ah, así es como se evitan las variables globales en C. Gracias por la información. – user1007968

0

lo que ifndef está protegiendo es uno .h incluido en un .c más de una vez. Por ejemplo

cosa. h

#ifndef 
#define 

int something = 0; 
#endif 

thing2.h

#include "thing.h" 

main.c

#include "thing.h" 
#include "thing2.h" 
int main() 
{ 
    printf("%d", something); 
    return 0; 
} 

si dejo ifndef a cabo a continuación, GCC se quejan

In file included from thing2.h:1:0, 
      from main.c:2: 
thing.h:3:5: error: redefinition of ‘something’ 
thing.h:3:5: note: previous definition of ‘something’ was here 
+0

Si bien su explicación es correcta, el problema de OP no es que las guardias de inclusión estén * en su lugar *. –

+0

@Als lo siento, OP? – manuzhang

+0

OP = Cartel original –