Doch
Die Definition der Vatiablen kommt in eine C-Datei (Modul)
type_t name1;
type_t name2 = initializer;
Die Deklaration kommt in den Header:
extern type_t name1;
extern type_t name2;
Hi,
mein Interrupt muss auf ein Statusflag zugreifen, dass als globale Variable im Hauptprogramm definiert wurde. Die Interrupt-Routine soll in einer extra Datei ausgelagert werden.
Wie teile ich jetzt dem Interrupt mit, dass die Variable existiert? Beim Kompilieren beschwert sich der Compiler, dass die Var undefiniert ist. Ich kann die Variable ja schlecht in eine Headerdatei schreiben, wie ich das bei Funktionen machen würde, dann wird die Var ja gleich mehrmals definiert.
OK, ist irgendwie eher eine Frage zu C-Softwaredesign als zum AVR. Vielleicht hat trotzdem jemand einen Tipp für mich.
Gruß
Arne
Doch
Die Definition der Vatiablen kommt in eine C-Datei (Modul)
type_t name1;
type_t name2 = initializer;
Die Deklaration kommt in den Header:
extern type_t name1;
extern type_t name2;
Disclaimer: none. Sue me.
Hi,
Sollte da nicht noch volatile hin?
MfG Alex
Nicht unbedingt. Kommt drauf an, was dein type_t ist:
typedef char volatile type_t;
Und das volatile ist schon in type_t!
Disclaimer: none. Sue me.
Hallo,
etwas umständlicher mache ich es immer. Dadurch erreiche ich aber, dass ich den Header in allen Sourcen includen kann (Auch im Source, in dem ich die Variable definieren will).
Das geht bei mir so:
Im Code mit der main-Funktion steht folgendes:
In allen anderen Sourcen lasse ich "define" und "undef" IMMER weg.Code:#define MAIN #include "header.h" #undef MAIN
In der Datei header.h steht dann für alle global zu vereinbarenden Variablen dies hier:
Der Vorteil ist, dass ich die Variable niemals mit verschiedenen Type schreiben kann, da sie ja nur einmal in header.h aufgeführt ist. Somit bekommen ich nie einen Warning wegen falscher typangaben im Source bzw. im Header.Code:#ifdef MAIN #define EXTERN #else #define EXTERN extern #endif EXTERN int g_variable_1; EXTERN char g_variable_2
Für die 'Interruptfesten' Variablen füge ich dann natürlich auch das 'volatile' hinzu.
Lieber Asuro programieren als arbeiten gehen.
Mit extern ist es kein Problem, wenn es mehrfach auftauch für die gleiche Variable. Es ist ja eine Deklaration (Bekanntmachung) und keine Definition (Oblekt anlegen)!
Bewährt hat sich in C/C++ folgendes:
source.h
source.cCode:#ifndef _SOURCE_H_ #define _SOURCE_H_ extern int var1; extern int volatile var2; extern void mache (int volatile * arg); #define MAKRO(x) ((x)+1) #endif /* _SOURCE_H_ */
Damit sind Makros und globale Variablen unf Funktionen überall benutzbar, wo der Header inkludiert wird.Code:#include "source.h" int var1; int volatile var2 = 42; void mache (int volatile * arg) { *arg = MACHE (*arg); var1 = var2; }
Es ist dann auch kein Thema, wenn über verschlungene Umwege ein Header 2 mal inkludiert wird.
Beispiele sind im Wiki bei den C-Quellen zur genüge.
Disclaimer: none. Sue me.
@SprinterSB
ich denke, dass du in deinem Muster in source.h von den Zeilen
#ifndef _SOURCE_H_
#define _SOURCE_H_
.
#endif /* _SOURCE_H_ */
sprichst/schreibst.
Nicht das wir uns falsch verstehen.
Ich meinte nicht ein doppeltes includen, auch nicht über verschlungen Pfade (kommt ja doch manchmal vor), sondern das Problem der DEFINITION und DEKLARATION.
Ich stelle mit meinem #define MAIN (Immer NUR im Source mit der main-Funktion!) nur sicher, dass die globalen Variablen nur GENAU EINMAL dann definiert werden wenn der Source mit der main-Funktion diese Headerdatei includet.
Das #ifndef ... , welches du beschreibst, ist natürlich ebenso wichtig. Allerdings nur um keine Warnings wegen doppelten defines zu bekommen. Diese Warnings könnten aber auf alle Fälle ignoriert werden, da ja das selbe aus der gleichen Datei defined wird.
Ich wollte mit meinem Zeug zeigen, dass ich den nicht zu ignorierenden Warning vermeiden kann, wenn ich eben NICHT an 2 Stellen Variablen und deren Datentypen (mal als Definition bzw. als Deklaration) schreiben muss.
Frage an @SprinterSB: In deinem Beispiel Source.c hast du auch die Funktion mache () mit extern void angegeben.
Jetzt kommen ich in's schleudern. Ist das OK, oder ist es nicht sogar falsch hier ein extern anzugeben?
@a//b
Kleines Muster in einfacher Variante:
Datei mit main() und deiner Verarbeitung. (z.B.: test.c)
In deiner Datei mit der Interruptfunktion ist folgendes:Code:char volatile g_flag; // Hier DEFINIERT void main () { Init (); g_flag = 0; while (1) { if (g_flag == 1) { // Tu das was nötig ist, da der Interrupt das Flag gesetzt hat. g_flag = 0; } } }Code:extern char volatile g_flag; // Nur DEKLARIERT SIGNAL (????) { // Nun ist etwas passiert g_flag = 1; }
Lieber Asuro programieren als arbeiten gehen.
...und bei typedef fliegen wir aus der Kurve, nämlich wenn eine Struktur in mehreren Modulen verwendet werden soll. Ebenso bei inline-Funktionen. Drittens hakt es aus, wenn du einer Variablen einen Initializer geben willst:Zitat von Sternthalergibt einen Fehler! Da eine Zeile Code sparen zu wollen ist IMHO an der falschen Stelle gespart.Code:extern int foo = 42;
Nein. Wenn die Funktion static (aufs Modul begrenzt) sein sollte, würde sie nicht im Header stehen, sondern alsZitat von Sternthaler
static void mache();
nur in dem Modul, wo sie gebraucht wird. Für globale (über mehrere Module hinweg) verwendbare Funktionen, gehören Prototypen in die jeweiligen Header. Und zwar im Header zur Quelle, welche die Funktion implementiert.
Disclaimer: none. Sue me.
sternthaler, Das Problem kommt doch nur daher, weil Du die Definition der Variablen in einem Header-File machst.
Common Sense bei C-Programmierung ist aber, die Definition von Variablen (und Funktionen) in einer C-Source, deren Deklaration (einschliesslich der Deklarationsspezifizierer z.B. extern) im Header zu machen.
Das spart die #ifdefs (mal ganz abgesehen von den Problemen, die Sprinter schon beschrieben hat).
Kann ich nicht nachvollziehen. Bei mir funktioniert folgendes ohne Probleme in einer in allen Sourcen includeten Headerdatei:Zitat von SprinterSBCode:/****************************************************************************** Typendefinition fuer die Sensoren */ typedef struct { unsigned char aktiv; // Startet/Stoppt die Sensoren unsigned char taster; // Tasterwert mit PollSwitch() geholt unsigned int batterie; // Batteriewert wie Batterie() unsigned int linie [4]; // 0:Links-Dunkel 1:Rechts-Dunkel // 2:Links-Hell 3:Rechts-Hell unsigned int rad [2]; // Zaehlerwerte der Radencoder } sens_t; #ifdef MAIN #define EXTERN #else #define EXTERN extern #endif /* Je nach Definition von EXTERN, werden die aufgefuehrten Variablen declariert oder definiert. Somit kann GENAU EIN SOURCE (Source mit der Main()-Funktion macht Sinn) die Variablen 'erstellen', aber alle anderen Sourcen koennen wegen der extern-Angabe auch auf die Variable zugreifen. */ EXTERN volatile sens_t sens; EXTERN int g_kp; EXTERN int g_ki; EXTERN int g_kd;Da kann ich nicht mitreden, da ich bis jetzt noch nie inline-Code benutzt habe.Zitat von SprinterSB
Das ist richtig, hier muss das Programm selbst initialisieren.Zitat von SprinterSB
Es geht mir nicht um die Zeile Code. Ich will nur sicherstellen, dass die Typen der ZWEI Zeilen Code IMMER identisch sind. Das erhalte ich über mein Konstrukt, da ich ja nur die eine Zeile habe.Zitat von SprinterSB
Hier ist das Potenzial für Differenzen, und wenn es nur nachträglich geschieht, dass der Typ der Variablen nur in einem Source geändert wird. Vergisst man, dass es noch den Header gibt, dann bekommt man zwar ein Warning beim Compilieren, aber es ist trotzdem möglich 2 verschiedene Datentypen zu nutzen. OK, wer die Warnings nicht beachtet hat selber Schuld, und wer vergisst, dass es 2 Source-Stellen gibt, ist gut beraten mal Urlaub zu machen. Aber genau dies ist schon immer eine extreme Gefahr bei uns in der Firma gewesen. (Bei dem Krempel von uns handelt es sich so ca. um 4500 Sourcen.)
Ja, bei static ist mir das schon klar, aber in deinem Beispiel zum source.c hast du als arbeitende Funktion (keine deklaration) diese als extern angelegt. Da wollte ich mal nachfragen, ob bzw. was ich da nicht verstehe.Zitat von SprinterSB
@ongni42
Ne, ne, ich unterscheide ja genau, dass ich nur einmal die Definition mache. Regeln tut das der Code mit dem #define EXTERN. Entweder hat EXTERN keinen 'Inhalt' oder es steht dann zur Deklaration eben doch das 'extern' dahinter.
OK, ich denke das nun jeder genug hat über dieses Thema zu debatieren. Ich hoffe hier niemandem auf die Füße getreten zu haben und wünsche euch (und mir) weiterhin schönen, fehlerfreien Code.
Lieber Asuro programieren als arbeiten gehen.
Lesezeichen