2011-04-05 17 views
43

Solo un programa simple, pero sigo obteniendo este error de compilación. Estoy usando MinGW para el compilador.C error: referencia indefinida a la función, pero está definido

Aquí está el archivo de cabecera, point.h:

//type for a Cartesian point 
typedef struct { 
    double x; 
    double y; 
} Point; 

Point create(double x, double y); 
Point midpoint(Point p, Point q); 

y aquí está point.c:

//This is the implementation of the point type 
#include "point.h" 

int main() { 
    return 0; 
} 
Point create(double x, double y) { 
    Point p; 
    p.x = x; 
    p.y = y; 
    return p; 
} 

Point midpoint(Point p, Point q) { 
    Point mid; 
    mid.x = (p.x + q.x)/2; 
    mid.y = (p.y + q.y)/2; 
    return mid; 
} 

Y aquí es donde entra en la edición del compilador sigo recibiendo.:

testpoint.c: undefined reference to 'create(double x, double y)'

Mientras está definido en el punto.c.

Este es un archivo separado llamado testpoint.c:

#include "point.h" 
#include <assert.h> 
#include <stdio.h> 
int main() { 
    double x = 1; 
    double y = 1; 
    Point p = create(x, y); 

    assert(p.x == 1); 
    return 0; 
} 

Estoy en una pérdida en cuanto a lo que podría ser el problema.

+0

¿Recibe cualquier otro mensaje? – JaredPar

+4

¿Podría publicar su archivo MAKE? Además, tienes 2 funciones principales definidas, eso no puede ser bueno. – George

+0

Probablemente una redefinición de 'main()' que es el punto de entrada a su programa. Deshazte de uno en 'point.c' – RageD

Respuesta

61

¿Cómo te va la compilación y el enlace? Tendrá que especificar ambos archivos, algo así como:

gcc testpoint.c point.c 

... para que sepa de vincular las funciones de los dos juntos. Sin embargo, con el código tal como está escrito en este momento, se encontrará con el problema opuesto: múltiples definiciones de main. Necesitarás/querrás eliminar uno (indudablemente el que está en el punto.c).

Editar: En un programa más grande, normalmente se compila y se vincula por separado para evitar volver a compilar todo lo que no ha cambiado. Normalmente se especifica lo que se debe hacer a través de un archivo MAKE y se usa make para hacer el trabajo. En este caso, tendría algo como esto:

OBJS=testpoint.o point.o 

testpoint.exe: $(OBJS) 
    gcc $(OJBS) 

La primera es simplemente una macro para los nombres de los archivos objeto. Obtienes se expande con $(OBJS). La segunda es una regla para decir a make 1) que el ejecutable depende de los archivos del objeto, y 2) diciéndole cómo crear el ejecutable cuando/si está desactualizado en comparación con un archivo objeto.

mayoría de las versiones de marca (incluyendo el de MinGW estoy bastante seguro) tienen una "regla implícita" incorporada a decir cómo crear un archivo de objeto desde un fichero fuente C. Normalmente se ve más o menos así:

.c.o: 
    $(CC) -c $(CFLAGS) $< 

Esto supone que el nombre del compilador de C está en una macro llamada CC (definido implícitamente como CC=gcc) y le permite especificar las banderas que le interesan en una macro llamada CFLAGS (por ejemplo, CFLAGS=-O3 para activar la optimización) y $< es una macro especial que se expande al nombre del archivo de origen.

Normalmente almacena esto en un archivo llamado Makefile, y para construir su programa, simplemente escriba make en la línea de comandos. Busca implícitamente un archivo llamado Makefile y ejecuta las reglas que contiene.

Lo bueno de esto es que make mira automáticamente las marcas de tiempo en los archivos, por lo que solo volverá a compilar los archivos que han cambiado desde la última vez que los compiló (es decir, archivos donde el "c" el archivo tiene una marca de tiempo más reciente que el archivo ".o" coincidente).

También tenga en cuenta que 1) hay muchas variaciones en cómo usar make cuando se trata de proyectos grandes, y 2) también hay muchas alternativas para hacer. Solo he llegado al mínimo de puntos altos aquí.

+1

Esto funciona, pero ¿es así generalmente cómo se enlazan/compilan los programas C de mayor tamaño? La palabra clave extern en el archivo de encabezado no parecía arreglar nada. – upswimsdn

+0

@upswimsdn: Consulte la respuesta editada. –

+0

Parece que solo respondiste lo suficiente como para resolver el problema de los solicitantes. Eso no es lo mismo que responder la pregunta. Por ejemplo, tengo exactamente la misma pregunta que en el título, pero todo está en un solo archivo. El objetivo de stackoverflow es proporcionar respuestas de búsqueda, no solo ayudar a alguien una vez y luego engañar a cualquiera que busque la misma pregunta. –

6

Creo que el problema es que cuando intenta compilar testpoint.c, incluye el punto.h pero no conoce el punto.c. Como point.c tiene la definición de create, no tener el punto.c hará que la compilación falle.

No estoy familiarizado con MinGW, pero necesita decirle al compilador que busque point.c. Por ejemplo con gcc es posible hacer esto:

gcc point.c testpoint.c 

Por supuesto, como others han señalado, también hay que quitar uno de sus main funciones, ya que sólo se puede tener uno.

3

agregar la palabra clave "externo" a las definiciones de funciones en point.h

+1

'extern' en una función no tiene ningún efecto en absoluto (al menos en estos días), ya que cada función declarada en un encabezado es pública/externa. –

2

tuve este problema recientemente. En mi caso, tenía mi IDE configurado para elegir qué compilador (C o C++) usar en cada archivo según su extensión, e intentaba llamar a una función C (es decir, desde un archivo .c) desde el código C++.

El archivo .h para la función C no estaba envuelto en este tipo de guardia:

#ifdef __cplusplus 
extern "C" { 
#endif 

// all of your legacy C code here 

#ifdef __cplusplus 
} 
#endif 

Podría haber añadido que, pero yo no quería que modificarlo, por lo que sólo se incluyeron en mi archivo C++, así: (Sombrero de punta a UncaAlby por su clara explicación de la effect of extern "C".)

extern "C" { 
#include "legacy_C_header.h" 
} 

Cuestiones relacionadas