C-Fehler: Undefinierter Verweis auf Funktion, aber definiert

Lesezeit: 7 Minuten

Benutzeravatar von upswimsdn
upswimsdn

Nur ein einfaches Programm, aber ich bekomme immer wieder diesen Compiler-Fehler. Als Compiler verwende ich MinGW.

Hier ist die Header-Datei, Punkt.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);

Und hier ist Punkt.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;
}

Und hier kommt das Compiler-Problem ins Spiel. Ich bekomme immer wieder:

testpoint.c: undefinierter Verweis auf „create(double x, double y)“

Während es in Punkt c.

Dies ist eine separate Datei namens 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;
}

Ich bin ratlos, was das Problem sein könnte.

  • Könntest du dein Makefile posten? Außerdem haben Sie 2 Hauptfunktionen definiert, die nicht gut sein können.

    – George

    5. April 2011 um 22:20 Uhr

  • Wahrscheinlich eine Neudefinition von main() das ist der Einstiegspunkt zu Ihrem Programm. Weg mit dem drin point.c

    – Wut D

    5. April 2011 um 22:25 Uhr

  • @upswimsdn, lag es an der doppelten Definition von main()?

    – Chan-Kim

    10. März 2016 um 5:55 Uhr

  • Ja, das war ein zusätzliches Problem, auf das ich gestoßen bin, aber das Hauptproblem bestand darin, die beiden Dateien nicht zusammen mit “gcc testpoint.c point.c” zu kompilieren (siehe die akzeptierte Antwort).

    – upswimsdn

    10. März 2016 um 16:13 Uhr

Benutzeravatar von Jerry Coffin
Jerry Sarg

Wie machst du das Kompilieren und Linken? Sie müssen beide Dateien angeben, etwa so:

gcc testpoint.c point.c

…damit es weiß, die Funktionen von beiden miteinander zu verknüpfen. Mit dem Code, wie er jetzt geschrieben ist, werden Sie dann jedoch auf das gegenteilige Problem stoßen: mehrere Definitionen von main. Sie müssen/wollen einen eliminieren (zweifellos den in Punkt.c).

In einem größeren Programm kompilieren und linken Sie normalerweise separat, um zu vermeiden, dass etwas neu kompiliert wird, das sich nicht geändert hat. Normalerweise geben Sie über ein Makefile an, was getan werden muss, und verwenden make um die Arbeit zu erledigen. In diesem Fall hättest du so etwas:

OBJS=testpoint.o point.o

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

Das erste ist nur ein Makro für die Namen der Objektdateien. Du bekommst es erweitert mit $(OBJS). Die zweite ist eine Regel, die make 1) mitteilt, dass die ausführbare Datei von den Objektdateien abhängt, und 2) ihr mitteilt, wie die ausführbare Datei erstellt werden soll, wenn/falls sie im Vergleich zu einer Objektdatei veraltet ist.

Die meisten Versionen von make (einschließlich der in MinGW, da bin ich mir ziemlich sicher) haben eine eingebaute “implizite Regel”, die ihnen sagt, wie sie eine Objektdatei aus einer C-Quelldatei erstellen sollen. Normalerweise sieht es ungefähr so ​​aus:

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

Dies setzt voraus, dass sich der Name des C-Compilers in einem Makro namens CC befindet (implizit definiert wie CC=gcc) und ermöglicht es Ihnen, alle Flags, die Ihnen wichtig sind, in einem Makro namens anzugeben CFLAGS (z.B, CFLAGS=-O3 um die Optimierung einzuschalten) und $< ist ein spezielles Makro, das auf den Namen der Quelldatei erweitert wird.

Normalerweise speichern Sie dies in einer Datei mit dem Namen Makefileund um Ihr Programm zu erstellen, geben Sie einfach ein make auf der Kommandozeile. Es sucht implizit nach einer Datei mit dem Namen Makefileund führt alle darin enthaltenen Regeln aus.

Das Gute daran ist, dass make prüft automatisch die Zeitstempel der Dateien, sodass nur die Dateien neu kompiliert werden, die sich seit der letzten Kompilierung geändert haben (dh Dateien, bei denen die “.c”-Datei einen neueren Zeitstempel hat als die entsprechende ” .o”-Datei).

Beachten Sie auch, dass 1) es viele Variationen bei der Verwendung von make gibt, wenn es um große Projekte geht, und 2) es auch viele Alternativen gibt. Ich habe hier nur das absolute Minimum an Höhepunkten erreicht.

  • Das funktioniert, aber werden größere C-Programme so allgemein verknüpft / kompiliert? Das Schlüsselwort extern in der Header-Datei schien nichts zu beheben.

    – upswimsdn

    5. April 2011 um 22:40 Uhr

  • Es scheint, als hätten Sie nur genug geantwortet, um das Problem des Fragestellers zu lösen. Das ist nicht dasselbe wie die Beantwortung der Frage. Ich habe zum Beispiel genau die gleiche Frage wie im Titel, aber alles ist in einer Datei. Der Zweck von Stackoverflow besteht darin, durchsuchbare Antworten bereitzustellen, nicht nur jemandem einmal zu helfen und dann jeden irrezuführen, der dieselbe Frage sucht.

    – Timothy Schwan

    20. Februar 2018 um 19:53 Uhr

  • @TimothySwan: Ich versuche, einigermaßen allgemeine Antworten zu geben, aber Es gibt eine Grenze. Jede Antwort in ein Lehrbuch zu schreiben, wird niemandem viel helfen – und wenn Sie es mit einer einzelnen Datei zu tun haben, selbst wenn Ihre Suche dies ergab, ist es immer noch so ziemlich eine andere Frage.

    – Jerry Sarg

    21. Februar 2018 um 6:41 Uhr

  • @JerryCoffin Danke für die Antwort! Dies gibt mir jedoch ein weiteres Problem: Wenn wir einige Bibliotheksfunktionen wie printf verwenden, fügen wir während des Kompilierens normalerweise keine Bibliotheksdateien zu gcc-Befehlen hinzu. Wir müssen nur stdio.h einbinden und es funktioniert. Gibt es einen Unterschied zwischen der von mir beschriebenen Situation und der im Problem?

    – Zirui Bai

    27. Februar 2020 um 9:47 Uhr

  • @ZiruiBai: Der einzige wirkliche Unterschied ist das Wann gcc (oder die meisten anderen Compiler) erzeugt den Linker, standardmäßig weist er den Linker an, auf die Standardbibliothek zu verlinken. Aber bei keiner anderen Bibliothek passiert das nicht (und es passiert normalerweise nicht einmal für mathematische Funktionen in der Standardbibliothek – zumindest müssen Sie das in den meisten Fällen explizit verlinken).

    – Jerry Sarg

    27. Februar 2020 um 9:55 Uhr

Ich hatte dieses Problem kürzlich. In meinem Fall hatte ich meine IDE eingestellt, um auszuwählen, welcher Compiler (C oder C++) für jede Datei entsprechend ihrer Erweiterung verwendet werden soll, und ich habe versucht, eine C-Funktion aufzurufen (dh von einer .c Datei) aus C++-Code.

Das .h Datei für die C-Funktion wurde nicht in diese Art von Schutz eingeschlossen:

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

Ich hätte das hinzufügen können, aber ich wollte es nicht ändern, also habe ich es einfach so in meine C++-Datei eingefügt:

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

(Hutspitze an UncaAlby für seine klare Erklärung der Wirkung von extern “C”.)

Benutzeravatar der Cam
Nocken

Ich denke, das Problem ist, dass beim Kompilieren von testpoint.c point.h enthalten ist, aber point.c nicht bekannt ist. Da point.c die Definition für hat createwenn point.c nicht vorhanden ist, schlägt die Kompilierung fehl.

Ich bin mit MinGW nicht vertraut, aber Sie müssen den Compiler anweisen, nach point.c zu suchen. Mit gcc könnten Sie beispielsweise Folgendes tun:

gcc point.c testpoint.c

Wie andere bereits betont haben, müssen Sie auch einen Ihrer entfernen main Funktionen, da Sie nur eine haben können.

Fügen Sie das Schlüsselwort „extern“ zu den Funktionsdefinitionen in point.h hinzu

Ich hatte ein ähnliches Problem beim Ausführen einer Reihe von .c-Dateien in einem Verzeichnis, die alle mit einer Header-Datei mit benutzerdefinierten Funktionsprototypen verknüpft waren. Ich lief:

$gcc -Wall -Werror -Wextra -pedantic -std=gnu89 *.c

Bekomme diese Fehler:

/usr/bin/ld: /tmp/ccovH4zH.o: in function `_puts': 3-puts.c:(.text+0x2f): undefined reference to `_putchar'
/usr/bin/ld: 3-puts.c:(.text+0x51): undefined reference to `_putchar'
/usr/bin/ld: /tmp/ccGeWRqI.o: in function `main': _putchar.c:(.text+0xe): undefined reference to `_putchar'
/usr/bin/ld: _putchar.c:(.text+0x18): undefined reference to `_putchar'
/usr/bin/ld: _putchar.c:(.text+0x22): undefined reference to `_putchar'
/usr/bin/ld: /tmp/ccGeWRqI.o:_putchar.c:(.text+0x2c): more undefined references to `_putchar' follow
collect2: error: ld returned 1 exit status

Hinweis: Alle Dateien wurden mit allen Funktionsdeklarationen mit derselben Header-Datei verknüpft.

Ich schaffe es, erfolgreich zu kompilieren, nachdem ich dem gcc-Compiler die Option -c hinzugefügt habe:

$gcc -Wall -Werror -Wextra -pedantic -std=gnu89 -c *.c

Diese laufen erfolgreich.

Nur für den Fall, dass jemand auf dasselbe stößt.

1420930cookie-checkC-Fehler: Undefinierter Verweis auf Funktion, aber definiert

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy