mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik C: Eine Funktion mehrmals in einem Projekt verwenden


Autor: Sven Scholz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe hier ein mieses Linker-Problem.
Ich habe eine Funktion test(), die ich in test.c geschrieben habe. Im 
Header-File test.h steht lediglich der Protyp etwa:

#ifndef TEST_H
#define TEST_H


// --- prototypes
void test(void);

#endif



Die Funktion wird jetzt von zwei *.c-Dateien aus aufgerufen. (timer.c, 
pwm.c)
Sie inkludieren beide die test.h, logisch.

Doch irgendwas läuft da noch faul. Einmal inkludieren funktioniert aber. 
Mehrmals leider nicht.

ERROR: The following symbols referenced could not be resolved...

Kann ich das irgendwie mit dem Schlüsselwort extern umgehen oder wie 
löse ich das Problem?

DANKE schon einmal.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Kann ich das irgendwie mit dem Schlüsselwort extern umgehen

ja.

Autor: Sven Scholz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gehört das extern denn auch mit in die test.c oder nur bei den 
Prototypen?
Vielen DANK.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Gehört das extern denn auch mit in die test.c oder nur bei den
>Prototypen?

Ich mache das so, dass ich alle Prototypen in einer header-Datei packe 
und diese dann "inkludiere". Jeder Prototyp bekommt dann extern. So hast 
du wenigstens alle Funktionen an einem Ort versammelt.

Autor: Sven Scholz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also dann nur bei den Prototypen und nicht etwa

extern void test()
{
      // Funktionscode
}

???

Autor: I_ H. (i_h)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kannst du nicht mit extern umgehen. Du hast scheinbar einmal 
vergessen die test.o mit reinzulinken, daher findet er die Funktion beim 
Linken dann nicht.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Also dann nur bei den Prototypen

Ja.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
extern hilft hier nichts.

Wie I_ H schon sagte:
Die wahrscheinlichste Ursache ist, dass du test.c nicht
mit in dein Projekt aufgenommen hast.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beispiel:

#include "define_prototypes.h"

extern void timer_init(void);

-------------------------

Datei main.c

void main(void)
{
    timer_init();
}

---------------------------

Datei init.c

void timer_init(void)
{
...
}

So machst du das z.B. auch, wenn du delays einbauen möchtest. Dann 
definierst du z.B. in der Datei delay.c deine Funktion, packst sie in 
die prototypen-Datei mit extern rein und inkludierst in jedem c-File 
diese Datei. Dann kannst du sie überall aufrufen.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS: Ohne Extern erhälst du die Fehlermeldung "implicit declaration of 
function...". Dein Compiler kann nicht "riechen", wo sich deine Funktion 
befindet. Somit ist extern hier essentiell wichtig.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das extern an dieser Stelle schadet zwar nicht, bringt
aber auch nichts.
Der Compiler kann auch so erkennen das es sich um eine
Deklaration handelt.

Wenn schon, dann mach es richtig:

Datei: Proto.h
*************
#ifndef PROTO_H
#define PROTO_H

void timer_init(void);

#endif

Datei main.c
************
#include "Proto.h"

int main(void)
{
    timer_init();
}

Datei: init.c
*************
#include "Proto.h"

void timer_init(void)
{
...
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:
> PS: Ohne Extern erhälst du die Fehlermeldung "implicit declaration of
> function...". Dein Compiler kann nicht "riechen", wo sich deine Funktion
> befindet. Somit ist extern hier essentiell wichtig.


Mit Verlaub: Aber du verzapfst Blödsinn.

Autor: Sir Sydom (sirsydom)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
extern ist hier fehl am Platz, dat hilft nix. Welcher Compiler?
Denn bei Funktionsprototypen ist ja extern idR eh default.


It can be used as a stylistic hint to indicate that the
function's definition is probably in another source file, but
there is no formal difference between

                extern int f();

        and

                int f();

References: ANSI Sec. 3.1.2.2, Sec. 3.5.1; ISO Sec. 6.1.2.2,
Sec. 6.5.1; Rationale Sec. 3.1.2.2; H&S Secs. 4.3,4.3.1 pp. 75-
6.

Ich tippe auch auf Linker Problem

Autor: Sven Scholz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ GAST

Das ist absolut richtig was du da schreibst, doch irgendwie ist mein 
Linker echt zu dumm. Mit extern vor jedem PROTOTYP hat nix gebracht. 
Echt übel.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven

Nochmal: Gast löst ein Problem, welches nicht existiert.

Dein Problem besteht höchst wahrscheinlich darin, dass du
vergessen hast, das zweite Source Code File deiner IDE oder
deinem makefile bekannt zu machen.
Alternativ könnte es auch ein simpler Tippfehler im Funktions-
namen sein.

'undefined reference' ist eine Fehlermeldung vom Linker und
nicht vom Compiler.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Mit Verlaub: Aber du verzapfst Blödsinn.

Mit Verlaub, du musst nicht deine primitive Geisteshaltung zeigen und 
jeden gleich anpissen.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Das ist absolut richtig was du da schreibst, doch irgendwie ist mein
>Linker echt zu dumm. Mit extern vor jedem PROTOTYP hat nix gebracht.
>Echt übel.

Hast du ein selbst geschriebenes Make-File? Ein Linker kann nicht zu 
dumm sein. Zeig mal bitte dein Make-File.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sir Sydom wrote:
> extern ist hier fehl am Platz, dat hilft nix. Welcher Compiler?
> Denn bei Funktionsprototypen ist ja extern idR eh default.
Rüchtüch. extern hat nur bei Variablen einen Effekt, weil der Compiler 
da nicht selber zwischen Deklaration und Definition unterscheiden kann. 
Bei Funktionsprototypen ist extern ziemlich sinnfrei.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:
>>Mit Verlaub: Aber du verzapfst Blödsinn.
>
> Mit Verlaub, du musst nicht deine primitive Geisteshaltung zeigen und
> jeden gleich anpissen.

Und du musst hier nicht noch weiter Mist erzählen obwohl es schon 
nachweislich widerlegt worden ist (Sir Sydoms Zitat)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:
>>Mit Verlaub: Aber du verzapfst Blödsinn.
>
> Mit Verlaub, du musst nicht deine primitive Geisteshaltung zeigen und
> jeden gleich anpissen.

Es geht nicht um anpissen.
Es geht darum, dass Sven ein ganz anderes Problem hat, als das
was du die ganze Zeit zu lösen versuchst (und das in Wirklichkeit
kein Problem ist).
Und dein Erklärung von 'extern' zeigt eigentlich nur, dass du
selbst 'extern' nicht richtig verstanden hast.

> Zeig mal bitte dein Make-File.

Endlich gehts in die richtige Richtung.

Autor: I_ H. (i_h)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist der Unterschied zwischen
int dummy1(void);

und
int dummy2;

?

Das erste ist ein PROTOTYP. Das heist das sagt dem Compiler "du, da 
fliegt irgendwo 'ne Funktion rum die so aussieht - die Funktion selber 
liegt aber ganz woanders, daher sag ich dir mal wie die aufgerufen 
werden muss".

Das zweite ist kein Prototyp. Da wird eine Variable definiert, so wie 
man eine Funktion implementiert.
Da die Variable aber auch woanders liegen kann, braucht man auch für 
Variablen Prototypen - das sieht dann so aus:
extern int dummy2;


Also merke:
int dummy1(void);
extern int dummy2;

gehören zusammen, und
int dummy1()
{
  // ...
}

int dummy2;

gehören auch zusammen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
I_ H. wrote:

> Das erste ist ein PROTOTYP.

Zufällig auch das. ;)  In erster Linie ist es aber eine
Funktionsdeklaration.  Man kann eine solche auch ohne einen
Prototypen schreiben:

int dummy1();

Das Schlüsselwort "extern" ist bei Funktionsdeklarationen
wahlfrei, da der Compiler aus dem Kontext (rundes Klammernpaar
mit abschließendem Semikolon) ableiten kann, dass es sich um
eine Funktionsdeklaration handelt.

> Das zweite ist kein Prototyp.

Kann es auch nicht sein, da das Wort "Prototyp" in C nur für
Funktionen benutzt wird.

> Da wird eine Variable definiert, so wie
> man eine Funktion implementiert.

Ja.

> Da die Variable aber auch woanders liegen kann, braucht man auch für
> Variablen Prototypen - das sieht dann so aus:
extern int dummy2;

Das ist richtig geschrieben, aber falsch bezeichnet.  Es ist
eine Variablendeklaration.  (Zur Erinnerung: das andere da oben
war eine Variablendefinition.)

Autor: I_ H. (i_h)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ging mir auch darum zu erklären wie was wozu benutzt wird, und nicht 
die exakten Begriffe zu verwenden, die mehr Verwirrung stiften als das 
sie weiterhelfen ;).

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die begriffliche Unterscheidung zwischen Deklaration, Definition und
Prototyp halte ich dennoch für essenziell genug, als dass eine
(öffentlich lesbare und daher potenziell von anderen als Referenz
benutzte) Erklärung dafür korrekt sein sollte.  Es ist ja nicht nur,
dass man das Prinzip verstanden haben muss.  Wenn man diese drei
Begriffe gedanklich nicht richtig sortiert, wird man zu gegebener
Zeit aus einer möglichen Fehlermeldung des Compilers (wie bspw.
"Function declaration is not a prototype") absolut nicht schlau.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.