Подтвердить что ты не робот

Ошибка 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;
}

Я не понимаю, в чем проблема.

4b9b3361

Ответ 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

Недавно меня озадачила похожая проблема. Затем заметил, что прямое объявление функции было "статическим", поэтому оно имело внутреннюю связь и было невидимым. Несмотря на то, что в определении не было ни одного ключевого слова.

Обязательно проверьте ваши декларации, ребята!