Ошибка: неопределенная ссылка на функцию, но она определяется


Просто простая программа, но я продолжаю получать эту ошибку компилятора. Я использую 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 45

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 " .)

Добавьте ключевое слово "extern"к определениям функций в пункте.h