Home › Foren-Übersicht › Mikrocontroller-Fernlehrgang (TFH) › wann genau Variablen/Funktionen extern

Foren-Übersicht

Sie müssen eingeloggt sein, um zu antworten.

1   2     nächste

Thema: wann genau Variablen/Funktionen extern

Autor Beitrag

AlexbeiElektor

32 Beiträge

Seltener Benutzer
Seltener Benutzer

Read post 28-08-2010 11:41

ich glaube ich sitze etwas auf dem Schlauch was dieses "extern" betrifft. Habe nun schon diverse Seiten im I-Net gelesen um diesem extern auf die Schliche zu kommen, aber irgendwie verstehe ich es immer noch nicht.

Da in den Lösungen z.B. bei der Datei cc03er.c bzw. cc03er.h z.B die Funktion "extern void seri_init(void);" extern declariert wird.
Warum?
Bisher dachte ich, nur wenn die Funktion/Variable aus einer anderen .c bzw. Headerdatei kommt muss diese mit "extern" bekannt gemacht werden, damit diese dann auch verwendet werden kann bzw. man damit arbeiten kann. Wieso wird hier nun mit extern gearbeitet?
Diese Funktion wird doch dort "erschaffen" warum also extern ?

Wenn ich diese Funktion z.B (void seri_init(void)) in einer anderen xyz.c Datei verwenden möchte, dann muss ich in der xyz.h Datei diese Funktion mit extern kennzeichnen(bekanntmachen), damit der Compiler weiß, die gibts schon wo anders.
Oder verstehe ich da was falsch?!

ich danke schon jetzt für die aufklärenden Worte

Beitrag editiert von AlexbeiElektor am 31-08-2010 06:38

AlexbeiElektor

32 Beiträge

Seltener Benutzer
Seltener Benutzer

Read post 17-09-2010 08:54

kann mir hierbei wirklich keiner helfen?

Majo

16 Beiträge

Neuer Benutzer
Neuer Benutzer

Read post 19-09-2010 18:54

Hi,

ich versuchs mal

Die Funktion void seri_init(void) wird deshalb als extern deklariert, weil du sie weil du sie ja in der main-Funktion verwenden wirst.

Also:
In der datei cc03er.c wird die Funktion programmiert.

Dein eigentliches Programm(also die Main-funktion) befindet sich aber in der "xyz.c". Die xyz.c ist dann quasi die Datei die vom Compiler übersetzt wird. Am Anfang bindest du die Header-Datei cc03er.h in das Projekt ein. Dort steht "extern void seri_init(void);", somit weiss der Compiler, dass er die Funktion nicht in der xyz.c suchen muss sondern in einer anderen *.c Datei, die zum Projekt gehört.

Ich hoffe ich konnte helfen, steht eigentlich alles in LB4 ab Seite 105.

Gruss Mario

AlexbeiElektor

32 Beiträge

Seltener Benutzer
Seltener Benutzer

Read post 20-09-2010 09:03

Hi Majo,
danke, ja die Seiten ab 105 habe ich mir sehr oft durchgelesen, aber was dieses "extern" angeht, ist dies doch sehr kurz gehalten.

werden wir doch mal konkret z.B., aus dem LB 5 die Lösung LCD_1.c
dort wird in der cco3er.h die Funktion "void seri_init(void)" als extern declariert.
ABER
Das ist doch nicht notwendig, da die Funktion void seri_init(void) doch dort "erschaffen" wird.
Durch die Einbindung(include) der cc03er.h in die lcd_1.c ist diese Funktion ja bekannt und kann in Main verwendet werden.

Angenommen ich würde bei diesem Beispiel die Funktion "void_seri_init(void) in einer anderen Funktion einer neuen "Funtionssammlung" verwenden wollen, dann muss ich dort die Funktion "void seri_init(void)" als extern declarieren da diese ja extern vorliegt.
Vielleicht denk ich auch einfach nur falsch kann schon sein...

Ich kann mir auf alle Fälle was die Musterlösungen angeht das ganze nicht nachvollziehen, da steht ja überall extern

JackDaniels

35 Beiträge

Seltener Benutzer
Seltener Benutzer

Read post 20-09-2010 15:27

Hallo ALexbeiElektor

Ich denke, wenn ich dein Problem richtig verstehe, das du einen
kleinen Gedankenfehler machst.

Anfangs haben wir ja immer die Funktion in das Main Programm
mit eingeschrieben. So auch die Funktion void seri_init(void).
Der Compiler konnte also alles was er benötigte in dem Main Programm finden.
Das ist so als hättest du einen Aktenordner mit nur einer Seite, da benötigt man kein Inhaltsverzeichnis.

Da unsere Programme aber immer umfangreicher werden, werden die Funktionen, die immer wieder benötigt werden, in eine eigene Funktionssammlung verschoben (void seri_init(void) zum Beispiel in die cc03er.c), um so immer wieder auf sie leicht
und schnell zurückgreifen zu können.
Das bedeutet also, dass dein Aktenordner mehr Seiten bekommt. Also wichtiger Inhalt aus der Hauptseite herausgenommen wird, um die Übersichtlichkeit zu wahren.
Nun kommt natürlich die Frage woher ich nun weiß was herausgenommen wurde und wo kann ich es finden?

Dafür gibt es die Header Datei. Diese ist im Grunde nichts anderes als ein Inhaltsverzeichnis von deiner Funktionssammlung, hier cc03er.c.
Die Funktion void seri_init(void) wird ja mit einigen anderen Funktionen in der cc03er.c deklariert.
Und die cc03er.h ist die Header Datei, also das zur cc03er.c gehörige Inhaltsverzeichnis.
Es ist wichtig, das dieses Inhaltsverzeichnis den gleichen Namen trägt wie die *.c Funktionssammlung auf die es verweisen soll.
Da die cc03er.h nur ein Inhaltsverzeichnis ist, werden dort keine Funktionen deklariert, es wird nur ein Verweis auf die dazugehörige cc03er.c gegeben. Woran erkennt nun der Compiler, dass er in die cc03er.h nachsehen muss?

In deinem Main Programm hast du die cc03er.h per include Anweisung eingebunden.

So:
#include "cc03er.h"

Nun weiß der Compiler, dass es nicht nur diese Datei, also das Main Programm gibt, sondern, dass es auch noch weitere Seiten in dem Programm gibt, die er nutzen kann.

Nun kommt der Compiler an folgende Stelle im Programm an:
seri_init();

Da nun der Compiler keine Funktion mit einem Funktionsblock vorfindet, weiß er, dass er auf einer anderen Seite nachsehen muss. Er erinnert sich, dass es noch ein Inhaltsverzeichnis
Namens cc03er.h gibt, das zuvor ihm durch die #include Anweisung zur Verfügung gestellt wurde.
In diesem Inhaltsverzeichnis sieht er die Funktion extern void seri_init(void);, nun schaut er nach wo er die vollständige Funktion bekommen kann, sieht also auf die „Seitenzahl“ die in unserem Fall durch ein extern angegeben ist.
Extern ist ja nun keine echte Zahl, da aber der Compiler durch dieses extern weiß, dass es eine Seite gibt, die genauso heißt wie das Inhaltsverzeichnis, nämlich cc03er, nur mit dem Unterschied, dass es sich bei den Seiten um eine *.c Datei handelt, schaut er im Ordner nach wo diese Datei ist. Und in dieser cc03er.c findet er die vollständige Funktion void seri_init(void) mit vollem Funktionsblock.
Diese bindet er dann in seine Datei mit ein.

Wenn ich deine Worte richtig verstanden habe, hast du die Funktion void seri_init(void) in der cco3er.h deklariert. Aber dieses ist nicht richtig! In der Header Datei werden keine Funktionen deklariert, es ist nur ein Inhaltsverzeichnis. In einem Inhaltsverzeichnis in einem Buch sind auch keine vollen Texte angegeben, nur ein Verweis auf die entsprechende Seite.

Also wichtig ist:
Header Datei und Funktionssammlung haben beide den gleichen Stammnamen.
In einer Header Datei werden keine Funktionen deklariert es ist NUR ein Inhaltsverzeichnis.

Hoffe, dass ich dir damit weiterhelfen konnte und ich dein Problem richtig verstanden habe.

LG Thomas

CTruller

14 Beiträge

Neuer Benutzer
Neuer Benutzer

Read post 20-09-2010 23:00

Sorry wenn ich mich auch noch zu Wort melde.

Hallo ALexbeiElektor und JackDaniels,

ich arbeite jeden Tag mit C und mit Mikrokontroller, deshalb erlaubt mir die Sache noch etwas klarer darzustellen. JackDaniels ist schon auf dem Richtigen Weg und auch ich hatte vor Jahren das Problem mit dem "Extern". Ich weiß auch jetzt nicht wie es in den Lehrbriefen dargestellt ist, Grundlegend ist aber wie folgt:

Wir haben, wie Ihr schon wisst nicht nur den Compiler, sonder
- einen Precompiler
- einen C-Compiler und
- einen Linker.
Wichtig ist der Precompiler, der ist nur ein Textersetzer und spart hauptsächlich Tipparbeit für dem Programmierer, er arbeitet wie folgt:
- die Anweisung (Makro) #define VAR MVar, wird bei jedem auftreten im Quellcode des VAR durch MVar ersetzt, ist Euch bestimmt schon bekannt. MVar könnte auch ein Wert z. B. 100 sein.
- die Anweisung #include "cc03er.h", sagt dem Precompiler hier den gesammten Inhalt der "cc03er.h" Datei rein kopieren und zwar alles mit allem was drinsteht. Sprich nach dem Precompiler steht in der xyz.c in der die include-Anweisung stand der gesamte Inhalt der "cc03er.h"-Datei und nicht ein Link zur "cc03er.c"-Datei, bitte nicht verwechseln.
Ok, der Precompiler hat seine Arbeit gemacht.
Jetzt kommt der C-Compiler und da war der JackDaniels schon auf dem richtigen Weg. Der C-Compiler geht die C-Datei durch und stösst irgendwo auf den Funktionsaufruf "seri_init();" im Quellcode, also er soll hier die Funktion "seri_init()" aufrufen, aber wo ist diese und jetzt kommts in der eingefügten h-Datei ist der hinweis auf diese Funktion, das es sie gibt, also schreibt der C-Compiler andiese Stelle _seri_init aufrufen. So und nun kommt der Linker, der weist den Funktionen und Variablen eine Speicheradresse zu, also er weiß an welcher Speicheradresse die Funktion "seri_init()" steht und wenn er den aufruf _seri_init hier starten liest trägt er statt der _seri_init die Speicheradresse der Funktion "seri_init()" ein und somit wird diese, die ja eine Subroutine ist und damit einen Rücksprung hat, an dieser Stelle gestartet.
Analog geht das ganze mit Variablen, nur hier muß das "Extern" beim zweiten Aufruf der H-Datei davor stehen da sonst der Compiler eine neu Variable anlegt und nicht die in einem anderen Modul vorhandene und als global (also überall erreichbar) definierte Variable verwendet.
Und hier ist das für mich komische denn alle C-Compiler die ich kenne, setzen einen Funktiondefinition in einer H-Datei automatisch auf global und extern, also ohne das ich es schreibe, ist in einer H-Datei der Text "void seri_init(void)" wird immer "global extern void seri_init(void)" geschrieben, was auch logisch ist da dem Linker immer eine Adresse für eine Funktion bekannt ist oder es gibt ne Fehlermeldung.
Anders ist es wie schon erwähnt mit den Variablen einmal muss sie ohne extern da sein (damit sie definiert wird) und bei jedem weiteren Definitionsaufruf muß extern davor stehen (sonst mekert der C-Compiler) damit sie nicht doppelt im Speicher erzeugt wird, der Linker würde auch noch mekern wenn es nicht schon der Compiler getan hätte.
Übrigends, wenn die Funktion "seri_init()" in der Datei der Main() steht aber hinter der Main-Funktion (also unten dran), muss da der Compiler von oben nach unten arbeitet, ein Vordefinitionsaufruf "void seri_init(void);" vor der "void Main(void)" stehen damit es nicht zu einer Fehlermeldung kommt. Es tut dem ganzen keinen Abruch wenn vor dem Vordefinitionaufruf ein extern steht, das stört nicht, wird einfach ignoriert.

Jetzt sollte es klar sein, dennoch Fragen dann hier stellen, ich kuck rein.

Gruß CTruller

AlexbeiElektor

32 Beiträge

Seltener Benutzer
Seltener Benutzer

Read post 23-09-2010 13:49

vielen Dank für Eure Antworten...

@CTruller, deinen Ausführungen kann ich am ehesten folgen.
@JackDaniels, vielleicht hab ich mich auch dauernd bei Dir verlesen, aber dann müsste ja immer das "extern" auftauchen, das kann aber sicherlich nicht der Fall sein.
Die Headerdatei enthält doch die Funktionsprototypen, also ist es doch eine "Art" Funktionsdeklaration um dem Compiler die "vorhandenen" Funktionen zu "zeigen, die es gibt".Und diese Prototypen werden durch das "include" durch den Precompiler "hineinkopiert"...so habe ich das auch verstanden.

Wenn ich mir also Eure Antworten so durchlese, denke ich schon, dass ich es nun einigermaßen verstanden habe und ich schon auf dem richtigen Weg war, vielleicht habe ich mich auch nicht genau genug ausgedrückt oder es liegt an dem verwendetem "Jens File Editor" das ich hier mit dem "extern" nicht klar gekommen bin.


Vielleicht kann mir ja noch jemand ein Beispiel nennen, bei dem das "extern" nicht benötigt wird, so wie ihr das ausdrückt ist das immer dabei?!
Mein Editor meckert aber wenn ich, wie hier beschrieben die "seri_init()" mit extern kennzeichne, daher muss ich das "extern" weglassen und dann funktioniert es...will ich die seri_init() in einer anderen "Funktionssammlung" nutzen kommt dort in die Headerdatei das seri_init() mit "extern" und kann so dort auch diese Funktion nutzen.
Ich seh schon ich strapazier Eure Nerven, sorry

Rai

30 Beiträge

Seltener Benutzer
Seltener Benutzer

Read post 23-09-2010 14:46

Hallo Alex,

ich habe mal in meinem Kopf etwas gewühlt und folgendes ausgegraben (Ohne Garantie)

- Wenn du eine Funktion in der Datei deines Hauptprogramms stehen hast dann befindet sich der Prototyp in DERSELBEN Datei wie die Funktion. D.h. hier brauchst du kein extern.

- Wenn der Prototyp in der .h Datei steht und die Funktion in der .c Datei dann sagst du dem Compiler/Precompiler/WasAuchImmer durch das "extern" dass die Funktion in einer anderen Datei wie der Prototyp steht.

Genauer kannst du das in dem Buch C-Programmierung Für 8051er Band 1 von BvB, PG, JK nachlesen. (Seite 316).

Viele Grüße

Rai

P.S. Entsorg bei gelegenheit mal den JFE. Seit ich Notepad++ nehme machts wieder viel mehr Spaß.

tom.hedd

7 Beiträge

Neuer Benutzer
Neuer Benutzer

Read post 02-11-2010 17:13

Und die cc03er.h ist die Header Datei, also das zur cc03er.c gehörige Inhaltsverzeichnis.
Es ist wichtig, das dieses Inhaltsverzeichnis den gleichen Namen trägt wie die *.c Funktionssammlung auf die es verweisen soll.


@Jack Daniels das bringt mich jetzt ins stutzen... Name der Header-Datei und der Funktionssammlung müssen identisch sein? Bin nämlich gerade an LB4 und bekomme das mit der header-datei nicht gebacken. Im Beispiel heißen die nämlich fkt_sammlung.c und fkt_proto. Habe es jetzt mit gleichen und ungleichen Namen ausprobiert, funktioniert aber beides nicht.

Meine Fehlermeldungen helfen mir auch nicht weiter...
myfkts.c .\myfkts_proto.h 7: Error: illegal character '#' myfkts.c .\myfkts_proto.h 7: Error: syntax error; found '21' expecting ';' myfkts.c .\myfkts_proto.h 7: Error: declaration syntax error
    myfkts.c .\myfkts_proto.h 7: Error: declaration syntax error
Muss man mit MakeWiz bei der WSP-Datei noch was einstellen, außer dem Hinzufügen der Funktionssammlung unter 'Components'?

tom.hedd

7 Beiträge

Neuer Benutzer
Neuer Benutzer

Read post 02-11-2010 21:09

Nabend!

Also ich habe mir das Problem (das ich im vorigen Beitrag genannt habe) noch einmal scharf angesehen und mir ist aufgefallen das es einen erheblichen Unterschied macht, ob ich bei fkts_proto.h nach der letzten Zeile noch eine Leerzeile oder ein Kommentar habe. Wenn keine weitere Lehrzeile folgt kommt die Fehlermeldung
Error: illegal character '#'

Ich weiß jetzt zwar das es so "irgendwie" nicht funktioniert, richtig verstehn kann ich es aber dennoch nicht.

Könnte mir das jemand vielleicht erklären...?

mfg

Sie müssen eingeloggt sein, um zu antworten.

1   2     nächste

Elektor 02/2012 am Kiosk

Gratis-Newsletter

Folgen Sie Elektor auf...