Hallo Forum und alle andere ))
ich habe versucht zu googeln, aber so richtig weiß ich nicht, nach was
ich suchen sollte.
Mein Problem:
Ich habe die eine "main.c" Datei, dort ist die Dateien "config.h" und
"wifi.h" inkludiert.
In "config.h" habe ich ein struct "wCLIENTCFG"
1
structwCLIENTCFG{
2
uint32configsaved;
3
uint32dhcp;
4
charssid[32];
5
charpassword[64];
6
charip[15];
7
charnetmask[15];
8
chargw[15];
9
chardns1[15];
10
chardns2[15];
11
};
So, wenn ich jetzt diesen Struct in "wifi.c" aufrufen will, sagt der
Compiler, dass dieser Sturct nicht bekannt ist, wenn ich aber in
"wifi.c" #include "config.h" machen, dann sagt der Compiler, dass der
Struct dopplet definiert wurde.
Wie kann ich das so machen, dass ich diesen Struct aus "wifi.c" aufrufen
kann?
Es kann natürlich auch sein, dass ich das ganz falsch mache, bin noch
nicht richig fit mit programieren in C.
Du könntest nach den Codeteilen suchen, in denen jeweils die Struktur
deklariert ist.
Je nach Compiler gibt es eine Option, mit der man die gesamte
Quellcodedatei sehen kann, nachdem die include-Anweisungen ausgeführt
worden sind - genauer eigentlich, nachdem die Preprozessor-Anweisungen
ausgeführt worden sind. Kommt auf den Compiler an.
In dem Ergebnis suchst Du denn einfach ob und wo und wieviele
Strukturdeklarationen für wCLIENTCFG zu sehen sind.
An sich ist das nicht schwer zu finden.
Schaue Dir genau die Fehlermeldung an. Auf welche Datei und welche
Codezeile bezieht sie sich? Daraus ist meist das wesentliche Problem zu
erkennen.
Falls Du möchtest, kannst Du hier auch den kompletten Quellcode und die
Fehlermeldung posten.
Danke für die schnelle Antworten, aber ich glaube ich das etwas unklar
beschrieben.
Hier noch mal mit Quelltext.
Meine main.c Datei (Auszug)
In main.c rufe ich diesen Struct auf, damit ich die Konfiguration in
Flash speicher kann.
1
...
2
#include"config.h"
3
...
4
...
5
...
6
structwCLIENTCFGclientConf;
Dieser Struct ist in "config.h" deklariert. Nach dem ich die
Konfiguration gespeichert habe, will ich diese in "wifi.c" wieder aus
dem Flash lesen, dafür benötige ich wieder den selben Struct, welchen
ich in "config.h" deklariert haben.
Nun zu meinem Problem, jetzt will ich diesen Struct in "wifi.c"
deklarieren, um die wifi Konfiguration zu lesen, leider sagt mir der
Compiler das:
1
user/wifi.c:105:33: error: 'wConfAddr' undeclared (first use in this function)
2
int readConf = spi_flash_read(wConfAddr*SPI_FLASH_SEC_SIZE, (uint32*)&wifiClientConf, sizeof(struct wCLIENTCFG));
das bedeutet ja, dass er diesen Struct nicht finden kann.
Wenn ich in die Datei "wifi.c" das hinzufüge:
1
...
2
#include"config.h"
3
...
und noch mal die Datei kompilieren will, dann bekomme ich diese
Fehlermeldung:
1
build/app_app.a(wifi.o):(.data+0x8): multiple definition of `wConfAddr'
was für mich bedeutet, dass es jetzt mehrmals definiert wurde.
So, die Frage ist, wie kann diesen Struct "wCLIENTCFG" in "wifi.c"
verwenden?
Du drückst Dich tatsächlich unklar aus.
Strukturen z.B. werden nicht "aufgerufen". Das tut man mit Funktionen
(oder Programmen). Es scheint mir auch so, dass Dir der Unterschied
zwischen "Definition" und "Deklaration" möglicherweise nicht klar ist.
Jedenfalls bleibt unklar, was denn nun der als Typ verwendete Bezeichner
"wConfAddr" mit der Struktur namens "wCLIENTCFG" zu tun hat.
Die zweite Meldung ist übrigens eine Meldung vom Linker und nicht vom
Compiler. Sie deutet darauf hin, und das entspricht auch der
Fehlermeldung, dass Du eine Variable namens "wConfAddr" mehrfach
definiert hast. Aber in der Parameterliste taucht der Bezeichner in der
Position eines Typs auf. Und das ganze hat, wiegesagt, mit der Struktur
"wCLIENTCFG" nichts zu tun.
Hoffe da hilft Dir ein wenig weiter.
Das Ganze sieht aus meiner Sicht so aus:
1. Wenn Du config.h nicht includest, fehlt Dir die Deklaration der
Struktur.
2. Wenn Du config.h includest, dann hast Du eine Variablendefinition
zuviel. Die von "wConfAddr".
Das Problem entsteht also nicht durch die Strukturdeklaration (das wäre
allenfalls so, wenn sich zwei Deklarationen widersprechen) sondern durch
die doppelte Variable.
Versuche das einmal nachzuvollziehen. Das scheint mir wichtig.
Als Lösung gibt es mehrere Möglichkeiten.
Die übliche ist: Die Variablendefinition durch eine
"guard"-Preprozessor-Definition jeweils mit der Speicherklasse "extern"
kennzeichnen oder nicht.
Das geht vermutlich im Moment noch über Deine Kenntnisse, aber das kann
man Dir, wenn Du willst, noch am Beispiel zeigen. Ich bin nur gerade zu
faul.
Da ich mich selbst auch falsch ausgedrückt habe, kann ich Dir sagen,
dass das "nicht so schlimm" ist. :-)
Also, die erste Fehlermeldung sagt etwas von einer fehlenden
Deklaration und nicht, wie ich schrieb, das selbe wie der
Linker-Fehler, der von einer doppelten Definition spricht.
Im Ergebnis also: "wConfAddr" ist nicht, wie Du möglicherweise annimmst
ein Typ sondern eine Variable.
Der Compiler sieht allerdings "wConfAddr" als Typ in der gezeigten
Zeile, da die Syntax von C an dieser Stelle sagt, dass nach der
öffnenden Klammer, als erster Teil eines Parameters ein Typ kommen muss
(mal von anderen Sachen abgesehen).
Da er den Typ aber nicht kennt, denn der ist scheinbar als ein
Variablenname verwendet, sagt er was von fehlender Deklaration.
Variablendefinitionen (und auch andere Definitionen) haben nichts in
Header-Dateien zu suchen.
Nur Variablendeklarationen (und andere Deklarationen) sollten dort
auftauchen, sonst nichts!
Bitte denke sorgfältig und lange über die Abläufe beim Kompilieren und
beim Linken nach, notfalls unter Zuhilfenahme einschlägiger Lehrbücher
und gezielter Fragestellung in einschlägigen Fachforen, solange bis Du
zweifelsfrei behaupten kannst begriffen zu haben warum das so
gefordert wird und was geschehen würde (und warum) sollte man je dagegen
verstoßen.
Bernd K. schrieb:> Variablendefinitionen (und auch andere Definitionen) haben nichts in> Header-Dateien zu suchen.
Die meisten Typdefinitionen gehören durchaus in Header-Dateien.
de1m schrieb:> user/wifi.c:105:33: error: 'wConfAddr' undeclared (first use in this> function)> int readConf = spi_flash_read(wConfAddr*SPI_FLASH_SEC_SIZE,> (uint32*)&wifiClientConf, sizeof(struct wCLIENTCFG));>> das bedeutet ja, dass er diesen Struct nicht finden kann.
Nein, das bedeutet, dass die Variable wConfAddr dem Compiler
unkbekannt ist. Über wCLIENTCFG meckert er hier ja nicht.
> Fehlermeldung:>> build/app_app.a(wifi.o):(.data+0x8): multiple definition of `wConfAddr'
Ich vermute, dass du in config.h die Variabele wConfAddr deklarierst
und definierst. Das heisst es wird Speicherplatz für diese Variabele
reserviert.
Da du config.h aber auch in main.c inkludierst, wird beim Compilieren
von main.c nochmal Speicherplatz reserviert und der Linker, der main.o
und wifi.o, zusammenschweissen will, beswchwert sich über die doppelte
Speicherzuweisung.
Die Lösung besteht darin, in config.h die Variabele nur zu definieren
(also ohne Speicherzuweisung):
1
externwCLIENTCFGwConfAddr;
Und dann in entweder main.c oder wifi.c wConfAddr zu deklarieren
(also Speicher zuzuweisen)
1
wCLIENTCFGwConfAddr;
Eine sauberere Lösung wäre aber wenn wifi.c Funktionen bereitstellen
würde, die es main.c erlaubt die Konfiguration ins Flash zu speichern
und daraus zu lesen, ohne dass main.c sich um die Adresse kümmern muss.
wifi.h
de1m schrieb:> Mein Problem:>> Ich habe die eine "main.c" Datei, dort ist die Dateien "config.h" und> "wifi.h" inkludiert.>> In "config.h" habe ich ein struct "wCLIENTCFG"
Ich habe den ziemlich bestimmten Eindruck, daß du Typdefinitionen und
Variablendeklarationen nicht unterscheiden kannst. Ich hätte dir zwecks
Erlernen dieses wesentlichen Unterschiedes zunächst das Programmieren in
Pascal empfohlen. Nachträglich tut das ebenso gut, also programmiere mal
ne Weile in Pascal.
Zu deinem Thema, also:
Erstens, wähle die Bezeichner deiner kreierten Typen sinnvoll. Ich würde
dir als Bezeichner deines struct's TClientCfg vorschlagen. Damit du (als
Eselsbrücke) am führenden T (wie "Typ") sehen kannst, daß hier eine
Typdefinition vorliegt. Wenn du sowas konsequent überall durchziehst,
dann machst du dir damit das Leben und das Lesen leichter.
Zweitens:
In eine .h Datei gehört nur das hinein, was man von dem Modul, der damit
gemeint ist, wirklich wissen MUSS. Und nicht mehr.
Drittens:
Klammere jeden Inhalt einer .h inetwa dieser Form
/* header zu config.c */
#ifndef CONFIGINCLUDED
#define CONFIGINCLUDED
struct TClientCfg
{ dword configsaved; // dein Kommentar dazu
dword dhcp; // dito
char ssid[32]; // ebenso
char password[64]; // usw.
char ip[15];
char netmask[15];
char gw[15];
char dns1[15];
char dns2[15];
};
extern struct Ottokar;
#endif
/* ende von config.h */
Also so etwa. Und in config.c wird natürlich config.h inkludiert UND du
vereinbarst dort deine tatsächliche Variable:
#include "config.h"
struct TClientCfg Ottokar;
So. Prinzip: Typangabe Variablenname;
Jetzt kannst du deine config.h überall einbinden wo du willst und von
dort aus auch auf Ottokar zugreifen.
Hast du das Prinzip dahinter jetzt verstanden?
W.S.
Ja, es stimmt, ich habe noch nicht viel Ahnung von C, habe einen kleinen
Projekt letztes Jahr gemacht, ansonsten habe ich damit nicht viel zu
tun.
Aber danke für die Hilfe, ich habe jetzt alles was zum Speicher Lesen
gehört in eine eigene Datei verschoben, damit klappt es mit Kompilieren,
bleibt aber nach dem Lesen hängen. Dazu habe ich einen anderen Topic
aufgemacht.