Globale Variablen - lokal neue Namen (Verteilte Variablen)

Hallo, ich habe Fragen zu Variablen.

Ich schreibe grade ein (für mich) sehr großes programm, im Grunde eine 16x16 LED-Matrix mit einem selbstgebauten Joypad. Die einzelnen Spiele sind sauber in Funktionen aufgeteilt.

Nun wird mir der Speicher (Ram) knapp. Ich möchte daher "Verteilte Variablen" machen. Im grunde also Globale variablen, die in einzelnen Funktionen andere Namen haben.

So stelle ich mir das vor:
Im Haptprogramm vor "void setup(){ ... }" gibt es die Variable "uint8_t Bigarray[256]". Das ist die Matrix in der z.B. die Spielinhalte der einzelnen Spiele sind. Sowie "int8_t var8" und "uint32_t var32".

Nun gibt es die Funktionen "void Labyrinth(){ ... }" und "void Racegame(){ ... }". In der Funktion Labyrinth möchte ich das "Bigarray" mit "playfield[]" ansprechen und in Racegame mit "streetmap[]". "var8" soll entsprechend in Labyrinth "direction" und in Racegame "speed" heißen. "var32" soll auch in jeder funktion anders heißen.

Wenn ich nun in Labyrinth eine Variable erzeuge: "uint8_t direction = var8" wird eine neue Variable im Ram erzeugt (der Zähler der den Speicher repräsentiert nach dem compilieren geht wieder einen hoch).

Ich will für jedes Spiel so ein dickes Array haben und einige einzelne Variablen, die Namen sollen jedoch auf die vor dem setup erzeugten Variablen zugreifen. Wie mache ich das?

Lies dich bezüglich Variablen in das Thema Sichtbarkeit und Gültigkeitsbereich ein.
Evtl. helfen auch Zeiger dein Problem zu lösen.

Die im Setup erzeugten Variablen sind nach Verlassen von Setup nicht mehr existent.
Globale Variablen sind immer und überall sichtbar. Was hindert dich daran, denselben Variablennamen (der global definierten Variable) in den einzelnen Funktionen zu nehmen?

Die Variablen werden vor dem Setup erzeugt, die sind global. Es hindert mich nichts daran, ich möchte nur passende Namen in den Funktionen haben.

Müssen die Variablen global sein? D.h. muss Du zwischen den Funktionen Daten austauschen?
Ansonsten definier dir dein 'Bigarray' lokal in den einzelnen Funktionen. Dann kannst Du dort individuelle Namen verwenden, und der Platz wird nur gebraucht, solange die Funktion läuft.

Die jeweils ausgewählte Funktion (Labyrinth, Racegame...) wird ständig (alle 20ms) wieder von Anfang an durchlaufen und beendet.

Daher will ich gern globale variablen nehmen.

Dan übergib dein 'Bigarray' beim Aufruf der Funktion als Parameter. Dann kannst Du innerhalb der Funktion mit dem Parameternamen darauf zugreifen. Und den kannst Du ja bei jeder Funktion individuell wählen.

Ja, dass ist eine Option. Jedoch würde ich das mit den lokalen neuen Namen auf globale Variablen doch mal interessieren.

Die Funktionen sind (ähnlich wie hier: a) in einer Liste definiert, die ich in der loop über den listenindex (Gamesactivegame ; ) aufrufe. Dann müssten bei mir mit der "normalen Parameterübergabe" alle funktionen die gleiche Anzahl und Art variablen haben.

a: FastLED/DemoReel100.ino at master · FastLED/FastLED · GitHub

Wenn dein uint8_t BigArray[256] den aktuellen Spielzustand für das jeweilige Spiel enthält, ist es wohl sinnvollerweise global oder wird als Funktions-Parameter mitgegeben.

Dann kannst du ihm in jeder Funktion eine passende Struktur mit passenden Namen verpassen.

uint8_t BigArray[256]; // Nur die ersten Bytes sind generell, der Rest hat je nach Spiel unterschiedliche Bedeutung 

enum Game {None=0, LABYRINTH, RACEGAME} game = None;
enum SpielStatus {Weiter=0, Unentschieden, Sieg1, Sieg2, Neu};

void setup() {}
void loop () {
  static enum Game game;

  switch (game) {
  case None: game = SelectGame((int*)BigArray); break;
  case LABYRINTH: {
    SpielStatus result = Labyrinth(BigArray);
    if (result == Neu) game = None;
  } break;

  } // end switch
}

struct LData{int zug;  byte feld[8][8]; byte posX; byte posY;};
SpielStatus Labyrinth ( void* data ) {
 LData& L = *(LData*)data;
 if (L.zug == 0) initLabyrinth();
 blink(L.posX, L.posY);
 //...
 return Weiter;
} 

void initLabyrinth() {}
void blink(byte X, byte Y) {}

enum Game SelectGame(int* zug) {
  if (millis() < 1000) { // Damit nicht alles wegoptimiert wird
     *zug = 0;  // Damit die Funktionen sich initialisieren können
     return LABYRINTH;
  }
  return None;
}

Nur um ein Struktur-Beispiel zu zeigen

staivoup:
Ja, dass ist eine Option. Jedoch würde ich das mit den lokalen neuen Namen auf globale Variablen doch mal interessieren.

Als Parameter übergeben.
Per Zeiger, oder als Referenz.

Das kannst du in jedem C++ Buch nachlesen.

Und was das mit den Namen soll?
Bahnhof!

michael_x: Vielen Dank, dass muss ich erstmal heute Abend verstehen.

Combie, referenz bei Wikibook (b) sieht gut aus. Funktioniert das auch mit Arrays?

b: C++-Programmierung/ Weitere Grundelemente/ Referenzen – Wikibooks, Sammlung freier Lehr-, Sach- und Fachbücher

Arrays übergibt man normal als Zeiger, da Array Variablen automatisch in Zeiger auf das erste Element zerfallen

int test[] = ...

func(test);

void func(int* arr)
{
}

Der Vorteil von Referenzen auf Arrays ist dass man in der Funktion sizeof() machen kann, aber normal übergibt man einfach zusätzlich die Größe des Arrays. Das ist eher ein Überbleibsel von C, aber hat sich so eingebürgert.

Wenn du Google bemühst kannst du auch rausfinden wie man Referenzen auf Arrays erzeugt, aber die Syntax ist nicht sehr intuitiv.

So:

using FettesArray = char[500];


FettesArray globalerName;



void verarbeiteFettesArray(FettesArray &lokalerName)
{
  // tuwas mit lokalerName
}


void setup() 
{
  verarbeiteFettesArray(globalerName);
}

void loop() {}

Ich muß mir das erstmal in ruhe ansehen. Vielen Dank.

In meinem Beispiel

...
struct LData{int zug;  byte feld[8][8]; byte posX; byte posY;};

SpielStatus Labyrinth ( void* data ) {
 LData& L = *(LData*)data;
 if ( L.zug == 0) init(); 
  ...
}

ist L eine Referenz auf eine LData Struktur, die als Zeiger ( void * ) erwartet wird und der man im Aufruf das mehrfach nutzbare Array in Form eines byte* übergibt.

Damit du heute Abend was zum Tüfteln hast. :wink:

Noch ein Tip am Rande: Nimm nicht Arrays für Sachen, die keine sind. Wenn bigArray[0] eine andere Bedeutung hat als bigArray[1], ist was falsch.
In meinem Beispiel teilen sich z.B. alle Spiele bigArray[0] und [1] als int Zug-Nummer. Das wäre also eher

struct CommonData{int zug; byte data[254];} bigData;

Aber das ist nur ein theoretisches Beispiel.

SpielStatus Labyrinth ( void* data ) {

LData& L = (LData)data;

Hier möchte ich Bedenken anmelden.

Denn, der Cast kann fürchterlich ins Auge gehen.
Er wird auch bei inkompatiblen Datentypen durchgeführt.

Ich würde global Unions benutzen, dort sieht man dann welche Namen für gleiche Speicherbereiche stehen.

Man könnte auch per #define neue Namen definieren.

Ob das alles irgendwie bei Deinem Problem hilft, da bin ich mir nicht sicher.

Er wird auch bei inkompatiblen Datentypen durchgeführt.

Ja klar. Das ist ja gerade das Ziel hier.

Wohl wissend, dass der Speicherbereich irgendwas sein könnte, übernimmt der Programmierer die Verantwortung dafür, dass es tatsächlich die Daten für ein bestimmtes Spiel sind.

Daher hab ich auch einen Extra-Merker am Anfang eingefügt, der in jedem Spiel sagt: Der Rest ist noch undefiniert. Das kann man auch weiter ausbauen, indem der Spieltyp mit abgelegt wird. (u.s.w.)

Hallo,

ich habe letztes Wochenende ganz stumpf Referenziert in den Funktionen, ohne Funktionsübergabe oder ähnliches:

uint8_t a = 1;  // eine Variable vor void setup


void labyrinth(){


uint8_t &r = a;  // Referenz auf die Variable a[/quote]
... Spielcode ...

}

Meine Programmstruktur habe ich unverändert gelassen. Das Bigarray heißt einfach überall Bigarray.

Ich habe mir jedoch alle Beipiele angesehen. Im nächsten Projekt (irgendwann) fliesst etwas davon ein. :slight_smile:

Ich vermute mal, daß Referenzen wie Pointer implementiert sind, d.h. längere Zugriffszeiten haben. Die kleinen AVR haben ja nur 3 Pointer-Register, da kann es schon mal eng werden.

Werden sei nicht.

Beim erstellen einer Referenz wird nur ein Bezeichner Alias erstellt.
Bei der Kompilation gehen alle Bezeichner verloren.

uint8_t &r = a;

Warum tut man sowas in einer Funktion?
Der Sinn sich mir nicht erschließt.