Globale Variablen bekannt machen

Gast #3916690
Lesenswert?

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!!!
Angehängte Dateien:
#3916789
Lesenswert?

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.
Moderator Persönliche Seite #3916796
Lesenswert?

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.
#3916845
Lesenswert?

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
void foo( int* HUGE dataPtr )
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.
Gast #3917004
Lesenswert?

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...
#3921395
Lesenswert?

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.
Moderator Persönliche Seite #3921414
Lesenswert?

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:
1
#if FOO == 1
2
   x
3
   foo ();
4
#else
5
   bar ();
6
#endif
#3921456
Lesenswert?

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:
1
#if FOO == 1
2
   foo ();
3
#elif FOO == 2
4
    bar ();
5
#elif FOO == 3
6
    baz();
7
#else
8
    #error Invalid value of FOO
Gast #3922672
Lesenswert?

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.
Gast #3930029
Lesenswert?

kopfkratz
Ja wo ist denn nun das eigentliche Problem ?
Üblicherweise macht man das so:
1
#ifndef GLOBALVARS
2
#define GLOBALVARS
3

4
int iIterator = 0;
5
char[19] cName;
6

7
volatile uint Flag = 0;
8

9
#endif
das dann im C oder CPP einbinden:
1
#include "globalvars.h"
Und ein gutes C/C++ Buch hilft da schon weiter :-P
#3930108
Lesenswert?

kopfkratzer schrieb:
> *kopfkratz*
> Ja wo ist denn nun das eigentliche Problem ?
> Üblicherweise macht man das so:
>
1
> #ifndef GLOBALVARS
2
> #define GLOBALVARS
3
> 
4
> int iIterator = 0;
5
> char[19] cName;
6
> 
7
> volatile uint Flag = 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.
1
#ifndef GLOBALVARS
2
#define GLOBALVARS
3
 
4
extern int iIterator;
5
extern char cName[19];
6
 
7
extern volatile uint Flag;
8
 
9
#endif


und in genau EINEM C-File kommt dann rein
1
...
2
#include "globalvars.h"
3

4
int iIterator = 0;
5
char cName[19];
6

7
volatile uint Flag = 0;
8
 
9
...

in allen ANDEREN C-Files lediglich ein
1
...
2
#include "globalvars.h"
3
...
Gast #3930131
Lesenswert?

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 ...
Persönliche Seite #3930135
Lesenswert?

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.
Gast #3930194
Lesenswert?

> Üblicherweise macht man das so:
1
> // globalvars.h
2
> ...
3
> int iIterator = 0;
4
> char cName[19];
5
> ...
> das dann im C oder CPP einbinden:
1
> #include "globalvars.h"

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.
Gast #3930235
Lesenswert?

> 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 ...)
#3930519
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren