Hallo Forum,
ich habe eine Frage die eventuel saublöd ist und mein signifikantes
Nichtwissen bloßstellt. Ich versuch es trotzdem:
Mein µC ist ein Arm7, ich mach das mit µVision3 und Realview-Compiler.
Mein kleines Projekt ist auf mehrere C-Dateien verteilt.
Die eine C-Datei, die Timer-Interrupt-Routine ist bei Eigenschaften ins
RAM gemappt, dort läuft sie schneller ab.
Die andere C-Datei ist das Hauptprogramm, das ein paar Drehschalter
(siehe Bild) abfragt und damit float-Werte aus Tabellen holt und damit
Berechnungen macht.
In der Timer-Interrupt-Routine ist dafür natürlich keine Zeit!
Wie kann ich der Timer-Interrupt-Routine die zwei berechneten Werte
mitteilen? Geht das über globale Variablen? Aber wie?
Ich steh im Moment neben mir und auf dem Schlauch!!!
Joachim B. schrieb:> Falk Brunner schrieb:>> globals.h>> extern volatile int foo;>> wäre nicht besser im globals.h
Sicherlich, auch wenns in diesem konkreten Beispiel nicht notwendig ist.
Include Guards sind aber ein anderes Thema
Peter Zz schrieb:> Vielen Dank an alle!>> Joachim B. schrieb:>> #define GLOBALS_H 1>> was bedeutet die 1 ?
Kann man natürlich weglassen, wenn man nur mit #ifdef prüft.
Ein
1
#define GLOBALS_H
reicht vollkommen aus.
Du kannst auch 42 hinschreiben ;-)
Frank M. schrieb:> Kann man natürlich weglassen, wenn man nur mit #ifdef prüft.>> Ein#define GLOBALS_H> reicht vollkommen aus.>> Du kannst auch 42 hinschreiben ;-)
vielleicht irre ich ja ich hatte mal ne Fehlermeldung weil ich keine 1
oder 42 dort hatte.
Ich verstehe ja was du sagst, aber lieber schreibe ich eine überflüssige
1 oder 42 hin als diesen blöden Fehler noch mal zu sehen, weiss aber
nicht mehr wieso und wo der Fehler war.
Joachim B. schrieb:> vielleicht irre ich ja ich hatte mal ne Fehlermeldung weil ich keine 1> oder 42 dort hatte.
Du irrst.
Ein
1
#define WAS_WEISS_ICH
ist immer eine gültige Preprocessor-Anweisung.
Ein
1
#ifdef WAS_WEISS_ICH
funktioniert immer - egal, ob WAS_WEISS_ICH definiert wurde oder nicht.
Das reicht für Include-Guards vollkommen aus.
Was anderes ist es, wenn Du mit
1
#if WAS_WEISS_ICH == 1
prüfst. Ältere Präprozessoren meckern dann, wenn WAS_WEISS_ICH nicht
definiert wurde - was ich auch richtig finde. Leider schlucken das auch
heutige gcc-Compiler ohne Fehlermeldung. Warum... weiß ich nicht. Ich
halte das für nicht richtig, da man Tippfehler wie diesen hier:
#if WASSSSS_WEISS_ICH == 1
dann nicht mehr bemerkt.
Frank M. schrieb:> Du irrst.>> Ein#define WAS_WEISS_ICH>> ist immer eine gültige Preprocessor-Anweisung.
OK dann lasse ich das 1 oder 42 zukünftig weg spart ja Tipperei und
mindestens ein Byte im Source :-)
Wie hat man bitte einen ARM7 und von derart grundlegenden Sachen keine
Ahnung? Ich will damit nur sagen: Is der Prozessor nicht evtl. ne Nummer
zu groß für dich???
Ingo
Joachim B. schrieb:> Frank M. schrieb:>> Du irrst.>>>> Ein#define WAS_WEISS_ICH>>>> ist immer eine gültige Preprocessor-Anweisung.>> OK dann lasse ich das 1 oder 42 zukünftig weg spart ja Tipperei und> mindestens ein Byte im Source :-)
Das muss ja auch möglich sein.
Das weg-definen von Dingen, ala
1
#define HUGE
2
3
voidfoo(int*HUGEdataPtr)
4
{
5
...
6
}
wird ja schon ewig so gemacht. Auf manchen Prozessoren/Compilern wird
HUGE dann eben so definiert, dass dort das Schlüsselwort definiert wird,
mit dem man dem Compiler sagt, dass er einen (Hausnummer) 24Bit Pointer
braucht, während das auf enderen Plattformen wieder nicht notwendig ist
und dem Prinzip nach, der Text 'HUGE' eben durch "nichts" zu ersetzen
ist, wodurch er effektiv wegfällt.
Ingo L. schrieb:> Wie hat man bitte einen ARM7 und von derart grundlegenden Sachen keine> Ahnung? Ich will damit nur sagen: Is der Prozessor nicht evtl. ne Nummer> zu groß für dich???
1. Learning by doing &
2. Ich bekamm im Forum oft genug den Rat:
> Wenn dein Programm & Daten nicht in einen ATtiny reinpassen,> dann nimm rechtzeitig einen größeren µC.
3. Der ARM7 µC kostet auch nur ca. 8€, ist also keine Sache...
Frank M. schrieb:> Ältere Präprozessoren meckern dann, wenn WAS_WEISS_ICH nicht> definiert wurde - was ich auch richtig finde. Leider schlucken das auch> heutige gcc-Compiler ohne Fehlermeldung. Warum... weiß ich nicht.
Weil es ISO-konform ist, wärend das von dir gewünschte Verhalten es
nicht ist. Was richtig ist, definierst nicht du, sondern die ISO-Norm,
und die sagt zu #if und #elif folgendes:
********************
After all replacements due to macro expansion and the defined unary
operator have been performed, all remaining identifiers are replaced
with the pp-number 0, and then each preprocessing token is converted
into a token.
********************
Heißt also: Wenn nach der Auflösung der Makros noch unaufgelöste Namen
da sind (weil diese nicht als Makro definiert sind), werden die durch 0
ersetzt.
Rolf Magnus schrieb:> Weil es ISO-konform ist, wärend das von dir gewünschte Verhalten es> nicht ist. Was richtig ist, definierst nicht du, sondern die ISO-Norm,> und die sagt zu #if und #elif folgendes:
Ich habe ja nicht gesagt, dass es falsch wäre. Ich finde es nur ...
unbequem. Ich weiß auch, dass sich der gcc-Preprocessor zumindest in den
90ern (evtl. auch noch später) anders verhalten hat.
Mit #ifdef kann ich prüfen, ob eine Preprocessor-Konstante überhaupt
definiert ist. Wenn ich früher bei #if versehentlich eine Konstante
hingeschrieben habe, die nicht definiert war, bekam ich eine schöne
Fehlermeldung und ich wusste sofort, wo ich nachbessern musste.
Das bekommt man nun nicht mehr. Ich müsste also heute, um mich wirklich
abzusichern, jedesmal schreiben:
1
#ifndef FOO
2
#error FOO not defined
3
#endif
4
5
#if FOO == 1
6
foo();
7
#else
8
bar();
9
#endif
Das finde ich halt unpraktisch. Von einem Preprocessor-Bug habe ich aber
nie geredet.
P.S.
Heute prüfe ich das so, indem ich unter das
#if FOO == 1
erstmal bewusst einen Syntaxfehler erzeuge, also z.B. ein einfaches x
eintippe. Wenn der Compiler dann meckert, weiß ich, dass die Konstante
an dieser Stelle wirklich definiert ist und auch einen Wert (!= 0) hat.
Also:
Frank M. schrieb:> Rolf Magnus schrieb:>>> Weil es ISO-konform ist, wärend das von dir gewünschte Verhalten es>> nicht ist. Was richtig ist, definierst nicht du, sondern die ISO-Norm,>> und die sagt zu #if und #elif folgendes:>> Ich habe ja nicht gesagt, dass es falsch wäre.
Naja, du hast es als "nicht richtig" bezeichnet. Das ist für mich das
selbe wie "falsch".
> Ich müsste also heute, um mich wirklich abzusichern, jedesmal schreiben:> #ifndef FOO> #error FOO not defined> #endif>> #if FOO == 1> foo ();> #else> bar ();> #endif
Sowas braucht man doch nur, wenn man mehr als zwei Möglichkeiten hat.
Dein Beispiel würde doch ohne Zahlenwerte und mit #ifdef gehen. Und für
mehr als zwei Fälle sollte man sowieso alle nicht definierten abfangen,
also z.B. so:
Joachim B. schrieb:> vielleicht irre ich ja ich hatte mal ne Fehlermeldung weil ich keine 1> oder 42 dort hatte.>> Ich verstehe ja was du sagst, aber lieber schreibe ich eine überflüssige> 1 oder 42 hin als diesen blöden Fehler noch mal zu sehen, weiss aber> nicht mehr wieso und wo der Fehler war.
Dann solltest du der Sache auf den Grund gehen, statt hier irgendwelche
Gerüchte in die Welt zu setzen. Millionen von C-Programmen funktionieren
ohne die "1" und das ist auch ok so.
kopfkratzer schrieb:> *kopfkratz*> Ja wo ist denn nun das eigentliche Problem ?> Üblicherweise macht man das so:>
1
>#ifndefGLOBALVARS
2
>#defineGLOBALVARS
3
>
4
>intiIterator=0;
5
>char[19]cName;
6
>
7
>volatileuintFlag=0;
8
>
9
>#endif
10
>
> das dann im C oder CPP einbinden:>
1
>#include"globalvars.h"
2
>
Genau so macht man das üblicherweise eben nicht. Denn genau dieses
mündet sonst in einer Verletzung der One Definition Rule bzw. in einem
"multiple definition" Fehler vom Linker.
Karl Heinz schrieb:> Genau so macht man das üblicherweise eben nicht. Denn genau dieses> mündet sonst in einer Verletzung der One Definition Rule bzw. in einem> "multiple definition" Fehler vom Linker.
Das ist mir persönlich noch nicht vorgekommen.
Deswegen ja
1
#ifndef XYZ
2
...
3
#endif
Der Compiler erkennt dann ja das das Include bereits definiert und
eingebunden ist.
Und mit "extern" zu arbeiten finde ich persönlich keinen guten Stil.
Aber jedem das seine ...
kopfkratzer schrieb:> Der Compiler erkennt dann ja das das Include bereits definiert und> eingebunden ist.
Tut er nicht. Dieser "include guard" hilft nur gegen mehrfaches
Einbinden in ein und derselben "translation unit", also dem einzelnen
C/C++-Source-File.
Da aber jedes auch nur mäßig interessante Programm aus mehreren,
separat voneinander zu übersetzenden Quelltextdateien besteht, versagt
der "include guard" hier, und der Kram wird in jeder einzelnen
"translation unit", in der der Kram eingebunden wird, wieder und wieder
definiert.
Und das mag der Linker nicht.
Wenn du das "üblicherweise" so machst, solltest du dir diesen
Anfängerfehler abgewöhnen. Das führt dazu, dass Sachen mehrfach
definiert werden (wenn z.B. dein globalvars.h von zwei Dateien benutzt
wird (und das ist ja der Sinn von .h-Files)).
Ein .h-File darf weder Code und noch Daten erzeugen. Punkt. Keine
Ausnahmen! In ein .h-File gehören Deklarationen (extern int
iIterator;), die entsprechenden Definitionen (int iIterator;) gehören
in ein .c-File.
Es mag vorkommen, dass man Dateien hat, die Code/Daten erzeugen und
included werden sollen. Eine übliche Konvention ist es, diesen Dateien
die Endung .inc zu geben. Aber auf keinen Fall .h.
> Und mit "extern" zu arbeiten finde ich persönlich keinen guten Stil.
Klingt wie "Flussmittel zu benutzen finde ich persönlich keinen guten
Stil." ;-)
"extern" ist keine Frage des Stils sondern eine Notwendigkeit. Die
einzige Art und Weise "extern" zu vermeiden, ist, alles in eine Datei
zu packen (inklusive aller benutzten Library-Routinen) und das hat mit
"Stil" nichts mehr zu tun.
Find dich einfach damit ab, dass man bei C Variablen/Funktionen, die in
mehr als einer Datei genutzt werden, an zwei Stellen "hinschreiben"
muss, einmal die Definition in dem .c-File und dann die Deklaration in
einem .h-File.
(Ja, es gibt noch inline-Funktionen ...)
kopfkratz schrieb
> Und mit "extern" zu arbeiten finde ich persönlich keinen guten Stil.> Aber jedem das seine ...
Stil? Das hat nichts mit Stil zu tun, sondern damit, dass du den
Unterschied zwischen einer Definition und einer Deklaration noch nicht
verstanden hast.
Es ist ja nicht so, dass ich ueber dieses Thema und seinen Zusammenhang
mit globalen Variablen noch nie eine lange Abhandlung fuer irgendjemand
geschrieben haette.