Prinzipiell willst du doch Folgendes erreichen
main.c
******
1 | can_msg_aufbau empfangsfach[8];
|
2 | can_msg_aufbau sendefach[8];
|
MCP.C
*****
1 | extern can_msg_aufbau empfangsfach[8];
|
2 | extern can_msg_aufbau sendefach[8];
|
Das sagt erst mal aus:
in main.c existieren die Variablen empfangsfach und sendefach.
In MCP.C wird (wegen dem extern) nur gesagt, dass es 2 Variablen
gibt, names empfangsfach bzw. sendefach. Wie gesagt: diese beiden
existieren irgendwo (naemlich in main.c. Das wissen aber nur wir,
der Compiler weis das erst mal nicht). Dem Compiler ist es beim
compilieren von MCP.C auch erst mal egal wo diese beiden Variablen
liegen, er muss nur wissen
* dass es sie gibt
* dass daher in weiterer Folge in MCP.c ein Variablenname von
empfangsfach kein Schreibfehler ist, sondern dass du tatsächlich
eine Variable damit meinst
* und natürlich welchen Datentyp sie haben.
Insbesondere letzteres muss er natürlich wissen, damit er bei
einer Arrayindiziegun aussrechnen kann, wo den das angesprochene
Element innerhalb des Arrays liegt.
Soweit so gut.
Der Compiler muss aber noch mehr wissen.
Wie ein Array aussieht, weiss er auch so. Aber wie der Datentyp
can_msg_aufbau aussieht weiss er nicht. Das muss man ihm daher
beschreiben.
Einschub: Denk immer daran: main.c und MCP.c werden unabhängig
voneinander compiliert! Wenn der Compiler MCP.c kompiliert, dann
sieht er nur dass, was in diesem File drinnen steht. Was in main.c
drinnen steht interessiert zu diesem Zeitpunkt nicht
D.h. aber auch.
Wenn der Compiler das hier compiliert
main.c
******
1 | // Erzeugen des Datentyps einer CAN-Botschaft
|
2 | //
|
3 | typedef struct
|
4 | {
|
5 | uint8_t IDh;
|
6 | uint8_t IDl;
|
7 | uint8_t EID8;
|
8 | uint8_t EID0;
|
9 | uint8_t DLC;
|
10 | uint8_t DATEN[8];
|
11 |
|
12 | } can_msg_aufbau;
|
13 |
|
14 |
|
15 | // Erzeugen der Datenfelder für Sende-/Empfangsfächer
|
16 | //
|
17 | can_msg_aufbau empfangsfach[8];
|
18 | can_msg_aufbau sendefach[8];
|
ist alles in Butter. Da werden 2 Variablen definiert, die beide
vom Datentyp Array von can_msg_aufbau sind. Wie ein can_msg_aufbau
aussieht, ist im vorher mitgeteilt worden-
Wenn der Compiler aber das hier compiliert:
MCP.c
*****
1 | extern can_msg_aufbau empfangsfach[8];
|
2 | extern can_msg_aufbau sendefach[8];
|
Dann hat er ein Problem. Zwar kennt er danach die beiden Variablen.
Er hat auch erkannt das es sich dabei um Arrays handelt.
Aber er weis nichts über den Datentyp can_msg_aufbau. Das würde er
gerne tun und auch tun muessen, denn er muss ja schliesslich
prüfen, ob sowas hier
überhaupt gültig ist. Dazu muss er aber wissen ob den eine
can_msg_aufbau überhaupt ein Feld namens EID8 besitzt und an
welcher Stelle in der Struktur diese steht.
Nur, wenn der Compiler nur das hier hat (und denk dran, was in
main.c steht interessiert nicht)
MCP.C
*****
1 | extern can_msg_aufbau empfangsfach[8];
|
2 | extern can_msg_aufbau sendefach[8];
|
dann kann er das schlicht und ergreifend nicht. Also muss man
ihm das beibringen
MCP.c
*****
// Erzeugen des Datentyps einer CAN-Botschaft
//
typedef struct
{
uint8_t IDh;
uint8_t IDl;
uint8_t EID8;
uint8_t EID0;
uint8_t DLC;
uint8_t DATEN[8];
} can_msg_aufbau;
// Erzeugen der Datenfelder für Sende-/Empfangsfächer
//
extern can_msg_aufbau empfangsfach[8];
extern can_msg_aufbau sendefach[8];
[/C]
Jetzt kann der Compiler alles notwendig aus MCP.c (und nur von
dort) ablesen um mit den beiden Variablen klarzukommen.
Jetzt kommt das grosse 'Aber'!
Natürlich ist sowas Fehleranfällig. Du musst die Struktur can_msg_aufbau
2-mal beschreiben: Einmal in main.c und einmal in MCP.c.
Das die beiden Beschreibungen exakt übereinstimmen sollten, brauche
ich wohl nicht extra zu erwähnen. Das diese Übereinstimmung von
niemandem (ausser dir) kontrolliert wird, brauche ich auch nicht
extra zu erwähnen. Wer solls auch machen? Wenn der Compiler main.c
compiliert kümmert ihn nur das was in main.c steht. Wenn der Compiler
MCP.c compiliert kümmert ihn nur das was in MCP.c steht.
Der Ausweg lautet: Ein Include File muss her.
Die Strukturdefinition wird dorthin ausgelagert. Dann kann ich
dieses Include File sowohl in main.c includieren als auch in MCP.c
includieren. Beim compilieren ist dadurch die Strukturdefinition
sowohl in main.c sichtbar, als auch in MCP.c. Und als Programmierer
hast du den Vorteil, dass du sie nur einmal schreiben musst. Und
da es sie in Textform nur einmal gibt, muessen daher die Definitionen
in main.c und MCP.c per Definition übereinstimmen.
structs.h
*********1 | typedef struct
|
2 | {
|
3 | uint8_t IDh;
|
4 | uint8_t IDl;
|
5 | uint8_t EID8;
|
6 | uint8_t EID0;
|
7 | uint8_t DLC;
|
8 | uint8_t DATEN[8];
|
9 |
|
10 | } can_msg_aufbau;
|
main.c
******
1 | #include "structs.h" // dadurch wird can_msg_aufbau eingeführt
|
2 | // was wiederuum notwendig ist, damit
|
3 | // der Datentyp für ...
|
4 |
|
5 | can_msg_aufbau empfangsfach[8];
|
6 | can_msg_aufbau sendefach[8];
|
7 |
|
8 | // bekannt ist. Der Compiler kann daher im
|
9 | // Speicher eine entsprechende Anzahl Bytes
|
10 | // für die beiden Variablen reservieren
|
MCP.c
*****
1 | #include "structs.h" // dadurch wird can_msg_aufbau eingeführt
|
2 | // was wiederuum notwendig ist, damit
|
3 | // der Datentyp für ...
|
4 |
|
5 | extern can_msg_aufbau empfangsfach[8];
|
6 | extern can_msg_aufbau sendefach[8];
|
7 |
|
8 | // bekannt ist. Dadurch weiss der Compiler
|
9 | // wie die Datentypen aussehen und wie der
|
10 | // Speicher, der an anderer Stelle reserviert
|
11 | // wurde, organisiert ist.
|