Forum: Compiler & IDEs Globale Variablen bekannt machen


von Peter Z. (Gast)


Angehängte Dateien:

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!!!

von Falk B. (falk)


Lesenswert?

@ Peter Zz (bastelboy)

>mitteilen? Geht das über globale Variablen?

Ja.

> Aber wie?
>Ich steh im Moment neben mir und auf dem Schlauch!!!

So


globals.h
1
extern volatile int foo;


globals.c
1
volatile int foo;

in main.c und isr.c per inlcude einbinden
1
#include "globals.h"

Siehe Interrupt

von Joachim B. (jar)


Lesenswert?

Falk Brunner schrieb:
> globals.h
> extern volatile int foo;

wäre nicht besser im globals.h?
1
#ifndef GLOBALS_H
2
#define GLOBALS_H 1
3
4
extern volatile int foo;
5
6
7
8
9
10
#endif

verhindert mehrfach Einbindung

von Karl H. (kbuchegg)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

Ich wollte keinen C-Kurs geben, nur das Prinzip zeigen.

von Peter Z. (Gast)


Lesenswert?

Vielen Dank an alle!

Joachim B. schrieb:
> #define GLOBALS_H 1

was bedeutet die 1  ?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 ;-)

von Joachim B. (jar)


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.

von Frank M. (ukw) (Moderator) Benutzerseite


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.

von Joachim B. (jar)


Lesenswert?

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 :-)

von Ingo L. (corrtexx)


Lesenswert?

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

von Karl H. (kbuchegg)


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.

von Peter Z. (Gast)


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...

von Rolf M. (rmagnus)


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.

von Frank M. (ukw) (Moderator) Benutzerseite


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

von Rolf M. (rmagnus)


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

von Mike A. (Gast)


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.

von kopfkratzer (Gast)


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

von Karl H. (kbuchegg)


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
...

von kopfkratzer (Gast)


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 ...

von Rufus Τ. F. (rufus) Benutzerseite


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.

von foobar (Gast)


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.

von foobar (Gast)


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 ...)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

foobar schrieb:
> bei C

Und nicht nur da, bei C++ ebenso.

von Karl H. (kbuchegg)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.