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