Ошибка: неопределенная ссылка на функцию, но она определяется
Просто простая программа, но я продолжаю получать эту ошибку компилятора. Я использую MinGW для компилятора.
Вот заголовочный файл, точка.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);
И вот точка.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;
}
И вот тут возникает проблема компилятора. Я продолжаю получать:
Контрольная точка.c: неопределенная ссылка на 'create (double x, double y)'
Пока он определен в точке.c.
Это отдельный файл под названием контрольная точка.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;
}
Я в недоумении, в чем может быть проблема.
4 ответа:
Как вы делаете компиляцию и связывание? Вам нужно будет указать оба файла, что-то вроде:
gcc testpoint.c point.c
... так что он знает, как связать функции из обоих вместе. Однако с кодом, написанным прямо сейчас, вы столкнетесь с противоположной проблемой: множественными определениями
main
. Вам нужно / нужно устранить один (несомненно, тот, о котором идет речь.с).Edit: в более крупной программе вы обычно компилируете и связываете отдельно, чтобы избежать повторной компиляции всего, что ничего не изменилось. Обычно вы указываете, что нужно сделать с помощью файла makefile, и используете
make
для выполнения работы. В этом случае у вас будет что-то вроде этого:Первый-это просто макрос для имен объектных файлов. Вы получаете расширяется сOBJS=testpoint.o point.o testpoint.exe: $(OBJS) gcc $(OJBS)
$(OBJS)
. Второе-это правило, чтобы сказать make 1) что исполняемый файл зависит от объектных файлов, и 2) сказать ему, как создать исполняемый файл, Когда/если он устарел по сравнению с объектным файлом.Большинство версий make (включая один из них в MinGW, я почти уверен) имеет встроенное "неявное правило", чтобы рассказать им, как создать объектный файл из исходного файла C. Обычно это выглядит примерно так:
.c.o: $(CC) -c $(CFLAGS) $<
Это предполагает, что имя компилятора C находится в макросе CC (неявно определенном как
CC=gcc
) и позволяет указать любые флаги, которые вас интересуют в макросе с именемCFLAGS
(например,CFLAGS=-O3
для включения оптимизации), а$<
- это специальный макрос, который расширяется до имени исходного файла.Вы обычно храните это в файле с именем
Makefile
, и чтобы построить свою программу, вы просто набираетеmake
в командной строке. Он неявно ищет файл с именемMakefile
и выполняет все правила, которые он содержит.Хорошим моментом этого является то, что
make
автоматически просматривает временные метки на файлах, поэтому он будет только повторно компилировать файлы, которые изменились с момента их последней компиляции (т. е. файлы, где ".c "файл имеет более позднюю временную метку, чем совпадение".o " файл).Также отметим, что 1) есть много вариантов в том, как использовать make, когда речь заходит о крупных проектах, и 2) есть также много альтернатив, чтобы сделать. Здесь я набрал лишь самый минимум высоких баллов.
Я думаю, что проблема в том, что когда вы пытаетесь скомпилировать testpoint.c, она включает пункт.h но он не знает о точке.c. начиная с пункта.c имеет определение для
create
, не имеющее точки.c вызовет сбой компиляции.Я не знаком с MinGW,но вам нужно сказать компилятору, чтобы он искал точку.c. например, с gcc вы можете сделать следующее:
gcc point.c testpoint.c
Конечно, как указалидругие , Вам также нужно удалить одну из ваших функций
main
, так как вы может быть только один.
У меня недавно был этот вопрос. В моем случае у меня был набор IDE, чтобы выбрать, какой компилятор (C или C++) использовать для каждого файла в соответствии с его расширением, и я пытался вызвать функцию C (т. е. из файла
.c
) из кода C++.Файл
.h
для функции C не был завернут в такого рода защиту:#ifdef __cplusplus extern "C" { #endif // all of your legacy C code here #ifdef __cplusplus } #endif
Я мог бы добавить это, но я не хотел его изменять, поэтому я просто включил его в свой файл C++ следующим образом:
extern "C" { #include "legacy_C_header.h" }
(кончик шляпы к Ункалби для его ясного объяснение эффекта extern " C " .)