2009-03-23 126 views
25

Soy C novato y solo estaba tratando de escribir una aplicación de consola con Code :: Blocks. Aquí está la (simplificado) Código: main.c:¿Cómo prevenir múltiples definiciones en C?

#include <stdio.h> 
#include <stdlib.h> 
#include "test.c" // include not necessary for error in Code::Blocks 

int main() 
{ 
    //t = test(); // calling of method also not necessary 
    return 0; 
} 

TEST.C:

void test() {} 

Cuando trato de instalar este programa, da los siguientes errores:

 
*path*\test.c|1|multiple definition of `_ test'| 
obj\Debug\main.o:*path*\test.c|1|first defined here| 

No hay forma de que multiplique la definición de prueba (aunque no sé de dónde viene el guión bajo) y parece muy poco probable que la definición se incluya de alguna manera dos veces. Este es todo el código que hay.

He descartado que este error se deba a algún conflicto de nombres con otras funciones o archivos que se llaman test o test.c. Tenga en cuenta que la definición múltiple y la primera están en la misma línea en el mismo archivo.

¿Alguien sabe qué está causando esto y qué puedo hacer al respecto? ¡Gracias!

Respuesta

66

En realidad se compila el código fuente de test.c dos veces:

  • La primera vez al compilar test.c sí,
  • La segunda vez al compilar main.c que incluye toda la fuente test.c.

Lo que se necesita en su main.c con el fin de utilizar la función test() es una simple declaración, no su definición. Esto se logra mediante la inclusión de un archivo test.h cabecera que contiene algo como:

void test(void); 

Esto informa al compilador que existe tal función con parámetros de entrada y tipo de retorno. Lo que hace esta función (todo dentro de { y }) queda en su archivo test.c.

En main.c, reemplace #include "test.c" por #include "test.h".

Un último punto: con sus programas siendo más complejos, se encontrará con situaciones en las que los archivos de encabezado se pueden incluir varias veces. Para evitar esto, las fuentes de cabecera a veces son encerrados por las definiciones de macros específicas, como:

#ifndef TEST_H_INCLUDED 
#define TEST_H_INCLUDED 

void test(void); 

#endif 
+0

Los nombres como _TEST.H_ que comienzan con un guión bajo y una letra mayúscula son ilegales en el código de usuario C; están reservados para los implementadores del compilador. –

+0

Debe proporcionar información sobre los parámetros para probar() en el archivo de encabezado, es decir, prueba de vacío(); -> prueba de vacío (vacío); – aib

+0

Acabo de tomar la interfaz sugerida en la pregunta, pero tiene razón: actualizo mi respuesta. – mouviciel

9

No debe incluir otros archivos fuente (* .c) en archivos .c. Creo que desea tener un archivo de encabezado ( .h) con la función de DECLARACIÓN de prueba y tener su DEFINICIÓN en un archivo .c por separado.

El error se debe a múltiples definiciones de la función de prueba (uno en test.c y otros en main.c)

4

incluido el archivo de aplicación (test.c) hace que se antepone a su main.c y cumplido allí y luego de nuevo por separado. Por lo tanto, la función test tiene dos definiciones: una en el código de objeto main.c y una en la de test.c, que le da una infracción ODR. Es necesario crear un archivo de cabecera que contiene la declaración de test e incluirlo en main.c:

/* test.h */ 
#ifndef TEST_H 
#define TEST_H 
void test(); /* declaration */ 
#endif /* TEST_H */ 
4

Si ha añadido a su test.c Código :: Blocks proyecto, la definición será visto dos veces - una vez a través de la #include y una vez por el enlazador. Es necesario:

  • quitar el # include "test.c"
  • crear un test.h archivo que contiene la declaración: prueba de vacío();
  • incluyen la test.h archivo en main.c

20

El guión se puso en su lugar por el compilador y usado por el enlazador. La ruta básica es:

main.c 
test.h ---> [compiler] ---> main.o --+ 
            | 
test.c ---> [compiler] ---> test.o --+--> [linker] ---> main.exe 

Por lo tanto, el programa principal debe incluir el archivo de cabecera para el módulo de prueba que debe consistir sólo en las declaraciones, como el prototipo de la función:

void test(void); 

Esto permite que el compilador saber que existe cuando se está compilando main.c pero el código real está en test.c, luego test.o.

Es la fase de enlace que une los dos módulos.

Al incluir test.c en main.c, está definiendo la función test() en main.o. Es de suponer que estás vinculando main.o y test.o, que contienen la función test().

+1

Up-voto para el diagrama agradable. –

+1

Otro voto favorable para el bonito diagrama de arte ASCII. –

4

Si está utilizando Visual Studio también se puede hacer "#pragma once" en la parte superior de la headerfile para lograr la misma cosa como el "#ifndef ..." - envolviendo. Algunos otros compiladores probablemente lo soporten también ... .. Sin embargo, no haga esto: D Quédese con el # ifndef-wrapping para lograr la compatibilidad del compilador cruzado. Solo quería que supieras que también podrías hacer #pragma una vez, ya que probablemente encontrarás esta afirmación un poco cuando leas el código de otras personas.

Buena suerte con ella

5

que tenía un problema similar y lo solucioné siguiente manera.

Resuelva la siguiente manera:

las declaraciones de prototipo de función y la variable global debe estar en test.h archivo y no se puede inicializar variable global en el archivo de cabecera.

Definición de la función y el uso de la variable global en el archivo test.c

si inicializar variables globales en la cabecera habrá error de seguimiento

definición múltiple de prueba `_ '| obj \ Debug \ main.o: ruta \ test.c | 1 | primero definido aquí |

Solo declaraciones de variables globales en el archivo de encabezado, la inicialización no debería funcionar.

creo que sirve

Saludos

Cuestiones relacionadas