Forum: Mikrocontroller und Digitale Elektronik auf variablen zugreifen


von sepp (Gast)


Lesenswert?

hallo

ich programmiere in c

geht das irgendwie, auf Variablen zuzugreifen, wenn sie im main 
definiert sind.

also ich will zB im interrupt.c einer funktion func(int i), die variable 
i übergeben, welche im main definiert ist.

von Stefan K. (stefan64)


Lesenswert?

Dazu brauchst Du eine globale Variable.
Eine "Variable in main" ist eine lokale Variable der Funktion main, auf 
die kannst Du nicht zugreifen.

Schreib einfach die Deklaration vor main(), damit wird die Variable 
global.
Also statt
1
int main ()
2
{
3
  int a;
4
  ...
1
int a;
2
3
int main()
4
{
5
  ...


Viele Grüße, Stefan

von Falk B. (falk)


Lesenswert?

@ sepp (Gast)

>ich programmiere in c

Und hast mal wieder vergessen, in ein C-Buch zu schauen.

>geht das irgendwie, auf Variablen zuzugreifen, wenn sie im main
>definiert sind.

Klar, in main.c

>also ich will zB im interrupt.c einer funktion func(int i), die variable
>i übergeben, welche im main definiert ist.

Nö. Dafür hat der liebe Gott bzw. die Jungs K&R die globalen Variablen 
erfunden, welche außerhalb einer Funktion definiert werden. Und beim 
Thema Interrupt sollte man das Thema volatile und atomarer Zugriff 
nicht vergessen.

von Bernd K. (prof7bit)


Lesenswert?

Stefan K. schrieb:
> Schreib einfach die Deklaration vor main(), damit wird die Variable
> global.

Unvollständig.

Wenn er aus dem Interrupt drauf zugreifen will muß die außerdem noch als 
volatile deklariert werden, also z.B. so:
1
volatile int a;

Sonst kommt in 4 Wochen ein Posting daß angeblich der Compiler defekt 
wäre.

Edit:
Und wenn sie breiter ist als das was der Prozessor in einer einzigen 
Instruktion lesen oder schreiben kann (also bei AVR wäre das alles was 
breiter ist als ein Byte) dann muß außerdem noch auf atomaren Zugriff 
geachtet werden: Interrupts sperren während die main darauf zugreift.

von Stefan F. (Gast)


Lesenswert?

Die Anfrage ist ziemlich unklar formuliert. Ich verstehe sie so:

Er hat in der Datei main.c eine globale Variable. In der Datei 
interrupt.c möchte er auf sie zugreifen.

Die einfachste Möglichkeit besteht IMHO darin, sie in der interrupt.c 
erneu zu deklarieren, aber mit dem Schlüsselwort "extern" davor. Also:

extern int i;

Bei Interrupts sollte man noch bedenken, was wohl passieren könnte, wenn 
das laufende Programm während des Zugriffs durch den Interrupt 
unterbrochen wird und dieser dann den Inhalt der Variable verändert.

Hier lohnt es sich, mal nach den Stichworten "volatile", "atomarer 
zugriff" und "interrupts sperren". Bei AVR auch "cli()" und "sei()".

Volatile ist unter Umständen auch ohne Interrupts nötig, sofern mehrere 
*.c Dateien schreibend auf die Variable zugreifen und sich dabei 
gegenseitig stören.

Mal angenommen, du hast in der main.c die Funktion verdopple_i() und in 
der interrupt.c steht irgendwo so etwas:
1
while (i<100)
2
{
3
   verdopple_i();
4
}

Dann brauchst du volatile. Denn ohne das volatile Schlüsselwort würde 
der vom Compiler erzeugte Maschinencode den Wert der Variable i in ein 
CPU Register kopieren, und dann mit 100 vergleichen. Da er nicht damit 
rechnet, dass i durch die Funktion verdopple_i() verändert wird, würde 
er beim nächsten Schleifendurchlauf nicht den aktuellen Wert von i 
prüfen, sondern die nun veraltete Kopie im Register.

"damit rechnen", dass eine Variable veränder wird, tut der Compiler nur 
bei Funktionen, die in der selben *.c Datei stehen. Mit dem 
Schlüsselwort "volatile" kopiert er i immer wieder neu in ein Register, 
bevor er mit 100 vergleicht. Das kostet Performance.

volatile extern int i;

Noch ein Tipp: Nenne die Variable nicht i, das provoziert 
Namenskonflikte. Vorschlag: main_global_pulse_counter

von sepp (Gast)


Lesenswert?

Stefanus F. schrieb:
> "damit rechnen", dass eine Variable veränder wird, tut der Compiler nur
> bei Funktionen, die in der selben *.c Datei stehen. Mit dem
> Schlüsselwort "volatile" kopiert er i immer wieder neu in ein Register,
> bevor er mit 100 vergleicht. Das kostet Performance.

würde er das nicht tun, müsste ich alle Variablen auch volatile in 
main.c deklarieren, richtig?

> volatile extern int i;
>
> Noch ein Tipp: Nenne die Variable nicht i, das provoziert
> Namenskonflikte. Vorschlag: main_global_pulse_counter

danke allen für die Unterstützung

von Stefan F. (Gast)


Lesenswert?

> würde er das nicht tun, müsste ich alle Variablen auch volatile in
> main.c deklarieren, richtig?

Nicht alle, aber ziemlich viele.

von sepp (Gast)


Lesenswert?

Ich habe eine weitere Frage.
Ich habe ein struct in commands.h erstellt.
1
typedef struct scharfeFrauen{
2
uint8_t blond;
3
uint8_t brünett;
4
}scharfeFrauen_t;
und Konstanten definiert
1
#define scharfeGeschoss  (scharfeFrauen_t) {0x00, 0x01}
2
#define scharfeGeschoss2 (scharfeFrauen_t) {0x02, 0x03}
und Array, den ich global nutzen muss, im selben Dokument commands.h 
erstellt und in main.c eingebunden:
1
static const uint8_t array[] = {scharfeGeschoss.blond, scharfeGeschoss2.blond};
jetzt meckert mir der Compiler troztdem, dass ich den array als const 
definieren muss.
Warum? Das ist er ja bereits.

von Thomas E. (thomase)


Lesenswert?

sepp schrieb:
> scharfeFrauen

sepp schrieb:
> scharfeGeschoss.blond

Solche politisch unkorrekten Ausdrücke sind bei gesitteten Compilern 
nicht erlaubt.

von A. S. (Gast)


Lesenswert?

Stefanus F. schrieb:
> "damit rechnen", dass eine Variable veränder wird, tut der Compiler nur
> bei Funktionen, die in der selben *.c Datei stehen.

Gibt es dafür einen Beleg? Wenn ich eine unbekannte Funktion aufrufe, 
ist doch jede globale Variable potentiell geändert.

Im Gegenteil: nur wenn sie in gleicher C-datei ist, kann der Compiler 
sehen, ob sie unverändert ist..

von sepp (Gast)


Lesenswert?

sepp schrieb:
> Ich habe eine weitere Frage.
> Ich habe ein struct in commands.h erstellt.typedef struct scharfeFrauen{
> uint8_t blond;
> uint8_t brünett;
> }scharfeFrauen_t;
> und Konstanten definiert#define scharfeGeschoss  (scharfeFrauen_t)
> {0x00, 0x01}
> #define scharfeGeschoss2 (scharfeFrauen_t) {0x02, 0x03}
> und Array, den ich global nutzen muss, im selben Dokument commands.h
> erstellt und in main.c eingebunden:static const uint8_t array[] =
> {scharfeGeschoss.blond, scharfeGeschoss2.blond};
> jetzt meckert mir der Compiler troztdem, dass ich den array als const
> definieren muss.
> Warum? Das ist er ja bereits.

Thomas E. schrieb:
> sepp schrieb:
>> scharfeFrauen
>
> sepp schrieb:
>> scharfeGeschoss.blond
>
> Solche politisch unkorrekten Ausdrücke sind bei gesitteten Compilern
> nicht erlaubt.

ok, beachte ich das nächste Mal.
An der Antwort wäre ich aber trotzdem interessiert.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

sepp schrieb:
> #define scharfeGeschoss  (scharfeFrauen_t) {0x00, 0x01}


Was soll das?

Überleg' Dir mal, was der Präprozessor daraus macht.
1
static const uint8_t array[] = {scharfeGeschoss.blond, scharfeGeschoss2.blond};
2
3
4
// wird zu
5
6
static const uint8_t array[] = {(scharfeFrauen_t) {0x00, 0x01}.blond, (scharfeFrauen_t) {0x00, 0x01}.blond};

Glaubst Du, daß der Compiler damit etwas anfangen kann?

von zyxw (Gast)


Lesenswert?

Auch wenn die Brünette schärfer ist als die Blonde:
Der Compiler wird sie wegen des Umlautes verschmähen.
Sieht man gleich daran, dass er rot wird.
Oder akzeptieren moderne Compiler inzwischen UTF?

von sepp (Gast)


Lesenswert?

Ich verstehe nicht so ganz

scharfeGeschoss ist vom Typ scharfeFrauen_t

Mit scharfeGeschoss.blond greife ich doch auf das 1. Element vom typedef 
struct

Wenn ich das mit einem Array in der main direkt mache, funktioniert das 
doch auch.. und ich kann auf die Elemente so zugreifen und übergeben.
Also versteht das doch der Compiler doch?
Ich wüsste sonst nicht warum das funktioniert.

von sepp (Gast)


Lesenswert?

zyxw schrieb:
> Auch wenn die Brünette schärfer ist als die Blonde:
> Der Compiler wird sie wegen des Umlautes verschmähen.
> Sieht man gleich daran, dass er rot wird.
> Oder akzeptieren moderne Compiler inzwischen UTF?

edit
habe ich nur hier falsch drin

von Klugscheisser (Gast)


Lesenswert?

ein #define ist aber kein Zugriff, sondern nichts anderes als eine 
Textersetzung.

Darum steht für den Compiler da:

Rufus Τ. F. schrieb:
> static const uint8_t array[] = {(scharfeFrauen_t) {0x00, 0x01}.blond,
> (scharfeFrauen_t) {0x00, 0x01}.blond};

von DPA (Gast)


Lesenswert?

Folgendes gillt nur für Globale Definitionen.

In C++ gäbe es constexpr, aber in c nicht. Der Wert der Variable ist 
erst nach dem Linken zur Runtime bekannt, aber nicht zur Compiler time. 
Man hätte in Standard theoretisch bei static const eine Ausnahme machen 
können, hat man aber nicht. Ausdrücke wie:
1
static const int a = 1;
2
static const int b = a;
sind deshalb nicht möglich. Es spielt dabei keine Rolle, ob man explizit 
b global Deklariert, oder implizit als Compound Literal anlegt. Bei 
Integern kann man immerhin noch auf enums zurück greifen, die sind echte 
Konstanten:
1
enum {
2
  a = 1
3
};
4
5
enum {
6
  b = a
7
};
8
9
const c = b;

Man kann jedoch Variablen Referenzieren:
1
int a = 1;
2
int* b = &a;
3
int* c = &(int){5};
4
int* d = (int[]){6};

Du könntest mit Macros auch sowas machen:
1
#define ZAHLEN \
2
  X(1,2) \
3
  X(2,3)
4
5
#define X(A,B) A,
6
int c[] = {ZAHLEN};
7
#undef X
8
9
int main(){(void)c;}

Auch mit Funktionen mit "__attribute__((constructor,used))" kann man 
einige Schweinereien anstellen. Ich verwende die gerne mit einem Macro 
für globale linked lists.

von Stefan F. (Gast)


Lesenswert?

@Achim S.

> Gibt es dafür einen Beleg?

Ich hasse diese Fragen. Welche Art von beleg würdest du denn 
akzeptieren? Ein Buch von mir? Ein Buch von Peter? Ein Video bei 
Youtube?

Ich habe das irgendwo gelesen, ausprobiert und für korrekt befunden. Das 
genügt mir. Wo ich die Weisheit her habe und wann und wie ich es 
überprüft habe, ist für mich unwichtig und daher vergessen.

Niemand zwingt Dich, mir zu glauben. Also lass es einfach bleiben, mir 
ist egal ob du gegen die nächste Wand läufst.

von sepp (Gast)


Lesenswert?

Also wie kann ich das dann machen, dass ich die Werte schön von einem 
anderen h-file aus per Hand zuerst definieren kann und diesem im Array 
übernommen werden, wenn ich nicht jedes Mal den Code durchgehen möchte 
und es passend ändere?

von Klugscheisser (Gast)


Lesenswert?

#define INIT_VALUES  \
{\
  .blond = 0x00,\
  .bruenett = 0x01,\
},\


scharfeFrauen_t woman = { INIT_VALUES };

von DPA (Gast)


Lesenswert?

sepp schrieb:
> Also wie kann ich das dann machen, dass ich die Werte schön von einem
> anderen h-file aus per Hand zuerst definieren kann und diesem im Array
> übernommen werden, wenn ich nicht jedes Mal den Code durchgehen möchte
> und es passend ändere?

Das hängt immer ganz von der Datenstruktur ab, die du definieren willst. 
Die Daten selbst würde aber auch in ein .c File legen. Wozu willst du 
eigentlich überhaupt das struct "scharfeFrauen" wenn du es sowieso nicht 
verwendest, um darin die Werte zu organisieren? Bzw. warum nicht einfach 
ein Array von "scharfeFrauen" erstellen, wozu die Arrays? Das erscheint 
mir redundant. Und spielt Speicherverbrauch oder Performance auch eine 
Rolle? Sonst könnte man die Arrays auch zur Laufzeit Alloziieren.

Oh, und bei meiner Variante mit dem "#define ZAHLEN" kannst du 
unterschiedliche Werte unterschiedlich expandieren, jenachdem, wie du X 
definierst:
1
#define X(A,B) A,
2
int alle_werte_a[] = {ZAHLEN};
3
#undef X
4
5
#define X(A,B) B,
6
int alle_werte_b[] = {ZAHLEN};
7
#undef X
Genügt das nicht?

Im Header ist dass ja dann einfach nur:
1
extern int alle_werte_a[];
2
extern int alle_werte_b[];

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.