Forum: Compiler & IDEs Verschiedene SourceCode-Dateien aufeinander zugreifen


von Master S. (snowman)


Lesenswert?

hallo

diesen link habe ich bereits gesehen
http://www.mikrocontroller.net/topic153712#1446709
leider stehe ich immer noch auf dem schlauch, wie ich auf funktionen 
einer anderen datei zugreifen kann und umgekehrt. wie soll ich das nun 
im folgenden beispiel machen, wenn ich in den entsprechenden c-dateien 
auf andere zugreifen will:

main.c
1
#include "main.h"
2
int c;
3
main() {
4
  functionA1();
5
  functionB2();
6
  VarExtA = 1;
7
  VarExtB = c;
8
}

main.h
1
#include"???"

fileA.c
1
#include "fileA.h"
2
int VarExtA;
3
int VarIntA;
4
functionExtA() {};
5
functionIntA() {
6
  VarIntA = VarExtB;
7
  functionB();
8
  PortpinX = 1;
9
};

fileA.h
1
#include"???"
2
#define PortpinX PortA.1
3
extern int VarExtA;
4
functionExtA() {};

fileB.c
1
#include "fileB.h"
2
int VarExtB;
3
int VarIntB;
4
functionExtB();
5
functionIntB() {
6
  VarExtA = 1;
7
  functionExtA();
8
  VarIntB = SettingB;
9
};

fileA.h
1
#include"???"
2
#define SettingB 0x01
3
extern int VarExtB;
4
functionExtB() {};

wenn ich alles bei allen einbinde, dann bekomme ich natürlich "multiple 
definitions of ...". bitte entschuldigt, ich habe nix bei google und in 
diesem forum gefunden, oder falsch gesucht. wäre schön, wenn mir jemand 
kurz sagen könnte, wie man sowas macht. vielen dank.

von A. F. (frankalicious)


Lesenswert?


von Master S. (snowman)


Lesenswert?

gut, danke für den link (wie man den auch immer findet? unter "artikel" 
sehe ich ihn nicht). anyway, ich lese den mal durch...

von Karl H. (kbuchegg)


Lesenswert?

fileA.h
1
#include"???"
2
#define PortpinX PortA.1
3
extern int VarExtA;
4
functionExtA() {};

Das letzte ist keine Funktionsdeklaration, sondern eine Definition. 
Logisch, dass du hier multiple definition Errors kriegst, denn in a.c 
gibt es ja die Funktion noch einmal.


fileA.h
1
#define PortpinX PortA.1
2
extern int VarExtA;
3
functionExtA();

von Master S. (snowman)


Lesenswert?

OK, müsste natürlich 'extern' heissen

z.b. fileA.h
1
#define PortpinX PortA.1
2
extern int VarExtA;
3
extern functionExtA();

dennoch kann ich nicht alles bei allen einbinden...
der text des links ist ja echt umständlich geschrieben; schwierig zu 
folgen. wieso nicht ein einfaches beispiel wie meines oben anstatt den 
vielen typedefs etc.?! ich will ja nur von verschiedenen c-files auf 
funktionen der anderen c-files zugreifen können...

von Karl H. (kbuchegg)


Lesenswert?

Master Snowman schrieb:
> OK, müsste natürlich 'extern' heissen

Nein, muss es nicht.
extern spielt bei Funktionen keine Rolle.

Aber dsa hier
1
functionExtA() {};

mal etwas umformatiert
1
int functionExtA()
2
{
3
};

ist eine Funktionsimplementierung!
Damit hast du 2 Implementierungen für dieselbe Funktion. Und das kann 
nicht sein.

> dennoch kann ich nicht alles bei allen einbinden...

Warum nicht?

Du bindest das ein, was du brauchst.
Wenn du dir filA.h ansiehst: Brauchst du dort irgendwas aus fileB.h? 
Nein. ALso bindest du es auch nicht ein.

Ja. Es ist wirklich so einfach. Schau dir das Header File an, lies es 
von oben nach unten durch und wenn da nichts vorkommt, was in einem 
anderen File ist, brauchst du auch nichts einbinden.

> der text des links ist ja echt umständlich geschrieben; schwierig zu
> folgen. wieso nicht ein einfaches beispiel wie meines oben anstatt den
> vielen typedefs etc.?!

Weil da auch ein paar Beispiele vorkommen sollen, die etwas mit der 
realen Welt zu tun haben. Deine Beispiele haben nichts mit der realen 
Welt zu tun. du hast nämlich in Wirklichkeit bei deinem Beispiel kein 
Problem, wenn du nur die C-Syntax richtig stellen würdest und den 
Unterschied zwischen Deklaration und Definition kennen würdest.

von Master S. (snowman)


Lesenswert?

na gut, ich gebs zu: es war etwas zu geschwind getippt, so dass 
deklaration und definition drunter litten :-( zumal ich erst jetzt mich 
darüber schlau gelesen habe. trotzdem: wie macht man's richtig?

main() wird wohl funktionieren, aber die internen A- und B-funktionen 
nicht...

main.c
1
#include "main.h"
2
void main() {
3
  functionA1();
4
  functionB2();
5
  VarExtA = 1;
6
  VarExtB = c;
7
}

main.h
1
#include "fileA.h"
2
#include "fileB.h"

fileA.c
1
#include "fileA.h"
2
int VarExtA;
3
int VarIntA;
4
void functionExtA() {}
5
void functionIntA() {
6
  VarIntA = VarExtB;
7
  functionB();
8
  PortpinX = 1;
9
}

fileA.h
1
#define PortpinX PortA.1
2
extern int VarExtA;
3
functionExtA();

fileB.c
1
#include "fileB.h"
2
int VarExtB;
3
int VarIntB;
4
void functionExtB() {}
5
void functionIntB() {
6
  VarIntB = VarExtA;
7
  functionExtA();
8
  VarIntB = SettingB;
9
}

fileA.h
1
#define SettingB 0x01
2
extern int VarExtB;
3
functionExtB();

> Weil da auch ein paar Beispiele vorkommen sollen, die etwas mit
> der realen Welt zu tun haben
das ist schön und gut, für solche die bereits solche sachen in der 
realen welt machen. für diejenige, die es erst verstehen müssen, aber 
recht hinderlich fürs verstehen.

von Karl H. (kbuchegg)


Lesenswert?

Die Vorgehensweise ist sehr einfach.

Du schreibst erst mal deinen C-Code. Zb fängst du an mit
FileA.C
1
int VarExtA;
2
int VarIntA;
3
4
#define PortpinX PortA.1
5
6
int functionIntA( void )
7
{
8
  VarIntA = VarExtB;
9
  functionB();
10
  PortpinX = 1;
11
};

Schau den Code durch. Damit du functionB aufrufen kannst, brauchst du 
einen Prototypen. Der kommt aus einem Header File (das du noch nicht 
hast), das aber FileB.h heissen wird. Also ergänzt du den Include


FileA.C
1
#include "FileB.h"
2
3
int VarExtA;
4
int VarIntA;
5
6
#define PortpinX PortA.1
7
8
int functionA( void )
9
{
10
  VarIntA = VarExtB;
11
  functionB();
12
  PortpinX = 1;
13
};

So. Damit ist FileAch vollständig. Da fehlt jetzt erst mal nichts mehr. 
Die Variable VarExtB wird ebenfalls über den include hereingezogen 
werden.
Jetzt gehst du her und überlegst: Was von dem Zeugs in FileA.C soll wer 
anderer verwenden können, welche Dinge muss FileA von sich preis geben. 
Da sind zu erst mal die beiden Variablen. Was soll mit denen geschehen. 
VarExtA soll von aussen zugreifbar sein, VarIntA nicht. Und dann 
natürlich die Funktion, die aufrufbar sein soll.

Also schreibst du ein Header File für FileA.c , in das all das 
reinkommt, was FileA.c nach aussen sichtbar machen will.

FileA.h
1
extern int VarExtA;
2
3
int functionA( void );

Die Variable kriegt ein extern davor, bei der Funktion nimmst du einfach 
die Implementierung weg und machst einen ; dahinter. (und wenn du willst 
kannst du auch extern davor schreiben, ist aber nicht notwendig)

Erneuter Blick aufs Header File. Kommt da irgendwas vor, was nicht 
Standard C Schlüsselwort ist? Nein. Nichts.
Also ist dieses Header File vollständig.

Zur Sicherheit ergänzt du jetzt in FileA.c noch einen Include auf das 
eigene Header File, denn dann kann der Compiler überprüfen ob die 
Angaben im Header File mit der tatsächlichen Implementierung 
übereinstimmen. Und da VarIntA von aussen nicht sichtbar sein soll (auch 
nicht durch Tricks), wird sie static gemacht.

FileA.c
1
#include "FileA.h"
2
#include "FileB.h"
3
4
int VarExtA;
5
static int VarIntA;
6
7
#define PortpinX PortA.1
8
9
int functionA( void )
10
{
11
  VarIntA = VarExtB;
12
  functionB();
13
  PortpinX = 1;
14
};


Dasselbe für FileB.c. Erst mal einfach runterschreiben
1
int VarExtB;
2
int VarIntB;
3
4
#define SettingB 0x01
5
6
int functionB( void )
7
{
8
  VarExtA = 1;
9
  functionA();
10
  VarIntB = SettingB;
11
};

damit functionA aufgerufen werden kann, braucht es einen Prototyp. Den 
kriegen wir von FileA.h
1
#include "FileA.h"
2
3
int VarExtB;
4
int VarIntB;
5
6
#define SettingB 0x01
7
8
int functionB( void )
9
{
10
  VarExtA = 1;
11
  functionA();
12
  VarIntB = SettingB;
13
};

Was noch? Nix mehr. In FileB.c wird sonst nix mehr verwendet was nicht 
entweder C Schlüsselwort oder im File selber oder durch einen include 
rreinkommt.

Dann wieder: das Header File für B schreiben. Dabei einfach nur 
überlegen: was soll von FileB.c nach aussen getragen werden.

FileB.h
1
extern int VarExtB;
2
3
int functionB( void );

und zur Sicherheit wieder ins eigene C-File includen und alle Variablen 
(oder auch Funktionen), die von aussen nicht sichtbar sein sollen, als 
static markieren.

FileB.c
1
#include "FileB.h"
2
#include "FileA.h"
3
4
int VarExtB;
5
static int VarIntB;
6
7
#define SettingB 0x01
8
9
int functionB( void )
10
{
11
  VarExtA = 1;
12
  functionA();
13
  VarIntB = SettingB;
14
};

damit bleibt nur noch main.c
Auch das schreiben wir erst mal einfach runter
1
int c;
2
3
int main()
4
{
5
  functionA();
6
  functionB();
7
  VarExtA = 1;
8
  VarExtB = c;
9
}

damit functionA aufgerufen werden kann, braucht es einen Prototypen. 
Woher kommt er? Aus FileA.h. Also gleich mal includen
1
#include "FileA.h"
2
3
int c;
4
5
int main()
6
{
7
  functionA();
8
  functionB();
9
  VarExtA = 1;
10
  VarExtB = c;
11
}

damit functionB aufgerufen werden kann, braucht es einen Prototypen. Wo 
kommt er her? Aus FileB.h. Also noch ein include
1
#include "FileA.h"
2
#include "FileB.h"
3
4
int c;
5
6
int main()
7
{
8
  functionA();
9
  functionB();
10
  VarExtA = 1;
11
  VarExtB = c;
12
}

Fehlt noch was? VarExtA ist durch den include von FileA.h bereits 
abgedeckt und VarExtB ist durch den include von FileB.h bereits 
abgedeckt. Also fehlt nix mehr. Auch in main.c sind damit alle Sachen 
abgedeckt und es ist in sich vollständig.

Compilieren, Linken, keine Fehler
(ausser der Tippfehler, die ich jetzt hier gemacht habe)


Das ist der Standardmechanismus.
Implementierung im C File schreiben
Überlegen, was von dieser Implementierung von aussen sichtbar sein soll.
Dasjenige kommt als Deklaration ins Header File, alles andere am besten 
static machen.
Für alles im C-File, das seinerseits woanders herkommt, gibt es einen 
include, der das jeweilig einbindet.


Und dann gibt es Sonderfälle und taktische Spielchen. Da kommt dann der 
Link von oben ins Spiel. Aber bis dahin ist das alles ganz banales 
Vorgehen nach Kochrezept.

von Master S. (snowman)


Lesenswert?

wow, vielen dank!!! :-) echt nett, die mühe die du dir gemacht hast. 
herzlichen dank! jetzt verstehe ich's :-)
ps: vieleicht im include-artikel auf deinen eintrag verweisen.

andere frage: wie wäre ich zu dem include-artikel gekommen? denn über 
hauptseite -> artikel finde ich ihn nicht (anderer titel?)

von Micha (Gast)


Lesenswert?

@Snowman:  kbuchegg hat es wirklich gut und ausführlich beschrieben.

Falls du mit Englisch kein Problem hast, kann ich dir den folgenden 
weiterführenden Artikel ans Herz legen:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=48535

Der Autor hat eine sehr gut verständliche Schreibe, ich hab aus seinen 
Tutorials schon einiges gelernt.

von A. F. (frankalicious)


Lesenswert?

Master Snowman schrieb:
> gut, danke für den link (wie man den auch immer findet? unter "artikel"
> sehe ich ihn nicht). anyway, ich lese den mal durch...

Gerne.
Artikelübersicht -> Alle Artikel

von Master S. (snowman)


Lesenswert?

@Micha: danke für den link. ich werde den mal in einer ruhigen "minute" 
ansehen.

> Artikelübersicht -> Alle Artikel
ach so ;-) :-)

von StinkyWinky (Gast)


Lesenswert?

Werden die Include-Guards stillschweigend vorausgesetzt oder braucht man 
das heutzutage nicht mehr?
1
#ifndef MODUL_H
2
#define MODUL_H
3
...
4
#endif // MODUL_H

von Der E. (rogie)


Lesenswert?

Und ob man die noch braucht. Es gibt Fälle, wo die mehrfache Einbindung 
auch durchaus gewünscht sein kann.
PS: Visual Studio kennt dafür auch eine #pragma once Anweisung, die das 
gleiche bewirkt.

von Karl H. (kbuchegg)


Lesenswert?

StinkyWinky schrieb:
> Werden die Include-Guards stillschweigend vorausgesetzt oder braucht man
> das heutzutage nicht mehr?

Irgendwo muss man ja mit der Erklärung mal anfangen :-)
Und da muss notwendigerweise dann so manches auf der Strecke bleiben, 
bis die Grundmechanismen verinnerlicht sind. Ich wage mal die 
Prophezeihung, dass der TO  in den nächsten Wochen auch ohne 
Include-Guards ganz gut über die Runden kommt. Und wenn er sie dann 
braucht, dann kommt er mit einem neuen Problem wieder.
Man kann einen Lernenden auch mit zu viel Information auf einmal 
überfordern.

von apr (Gast)


Lesenswert?

Man braucht sie zudem noch sehr selten...

von Master S. (snowman)


Lesenswert?

> Man kann einen Lernenden auch mit zu viel Information auf
> einmal überfordern.
danke, genau so ist es. mit dem include-artikel war und bin ich 
überfordert. mit deiner anleitung/erklärung bin ich sehr glücklich und 
hat mir viel geholfen fürs verstehen und mein problem hat hat sich mehr 
als nur gelösst (nicht nur problem glösst, sondern ich komme jetzt sogar 
draus :-) ).
man kann natürlich auch jemandem ein düsenjet erklären versuchen; wenn 
dieser aber noch nichteinmal ein fahrrad gsehen hat...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Master Snowman schrieb:
>> Man kann einen Lernenden auch mit zu viel Information auf
>> einmal überfordern.
> danke, genau so ist es. mit dem include-artikel war und bin ich
> überfordert.

Bei den Artikeln darfst du auch überfordert sein!

Es gibt mindestens 4 Artikel im Wiki die sich eher schlecht als recht 
versuchen des Themas anzunehemn, mehr verwirren als klären und teilweise 
sogar sich widersprechende Empfehlungen und Vorgehensweisen propagiern.

Den ganzen Kladderadatsch will ich schon ewig mal aufräumen und neu 
strukturieren, aber sooo wenig Zeit :-(

von Rolf M. (rmagnus)


Lesenswert?

StinkyWinky schrieb:
> Werden die Include-Guards stillschweigend vorausgesetzt oder braucht man
> das heutzutage nicht mehr?

Sie sind nicht vorgeschrieben. An den Mechanismen, nach denen C 
funktioniert, hat sich aber nichts geändert. Daher sind die genauso 
wichtig, wie sie schon immer waren.

apr schrieb:
> Man braucht sie zudem noch sehr selten...

Naja, sobald man halt mit Headern arbeitet. Wenn das bei dir selten ist, 
sind deine Programme entweder alle sehr klein oder sehr unübersichtlich 
;-)

von apr (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Naja, sobald man halt mit Headern arbeitet. Wenn das bei dir selten ist,
> sind deine Programme entweder alle sehr klein oder sehr unübersichtlich
> ;-)
nö -- wer mit Headern arbeitet braucht sie noch lange nicht. Erst wenn 
man unbedingt Header mehrfach einbinden möchte und in denen auch noch 
die richtigen Dinge schreibt...

von Rolf M. (rmagnus)


Lesenswert?

Ok, da hab ich wohl bei deinem ersten Posting den Smiley zwischen den 
Zeilen übersehen.

von apr (Gast)


Lesenswert?

Wie wäre es mit:
"Man braucht sie zudem noch, aus syntaktischen Gründen notwendigerweise, 
eher selten..."

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.