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


von Sven Scholz (Gast)


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.

von Gast (Gast)


Lesenswert?

>Kann ich das irgendwie mit dem Schlüsselwort extern umgehen

ja.

von Sven Scholz (Gast)


Lesenswert?

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

von Gast (Gast)


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.

von Sven Scholz (Gast)


Lesenswert?

Also dann nur bei den Prototypen und nicht etwa

extern void test()
{
      // Funktionscode
}

???

von I_ H. (i_h)


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.

von Gast (Gast)


Lesenswert?

>Also dann nur bei den Prototypen

Ja.

von Karl H. (kbuchegg)


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.

von Gast (Gast)


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.

von Gast (Gast)


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.

von Karl H. (kbuchegg)


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
*************
1
#ifndef PROTO_H
2
#define PROTO_H
3
4
void timer_init(void);
5
6
#endif

Datei main.c
************
1
#include "Proto.h"
2
3
int main(void)
4
{
5
    timer_init();
6
}

Datei: init.c
*************
1
#include "Proto.h"
2
3
void timer_init(void)
4
{
5
...
6
}

von Karl H. (kbuchegg)


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.

von Ing-Dom (Firma: OpenKNX) (sirsydom)


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

von Sven Scholz (Gast)


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.

von Karl H. (kbuchegg)


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.

von Gast (Gast)


Lesenswert?

>Mit Verlaub: Aber du verzapfst Blödsinn.

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

von Gast (Gast)


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.

von Johannes M. (johnny-m)


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.

von Simon K. (simon) Benutzerseite


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)

von Karl H. (kbuchegg)


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.

von I_ H. (i_h)


Lesenswert?

Was ist der Unterschied zwischen
1
int dummy1(void);

und
1
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:
1
extern int dummy2;


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

gehören zusammen, und
1
int dummy1()
2
{
3
  // ...
4
}
5
6
int dummy2;

gehören auch zusammen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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:
1
extern int dummy2;

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

von I_ H. (i_h)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.