Was bedeutet 'Main loop avoiding the GCC "optimization"'

Hallo Leute,

ich schaue mir gerade den Code meines Arduino-Theremins an um ihn zu verstehen.

die loop-Function sieht (gekürzt) so aus :

/* Main Loop */
void loop() 
{
mloop:                                        // Main loop avoiding the GCC "optimization"
sintable_counter_l++; // Check State only every halve second 

[ weiterer Code - Ende eines if-Statements]  

 if (vol_v < 0)
  {
    vol_v = 0;
  } ;
  vol8 = vol_v >> 4;

  flag_vol = false;                   // Clear volume flag
}

goto mloop;                           // End of main loop
}

Was will der Programmierer mir mit diesem "optimization"- Kommentar sagen ?

Danke und Grüße

Harry

Schwachsinn!
ohne Gewähr

Das wohl jemand den Compiler austricksen. Das ist selten eine gute Idee

Goto ist (fast) immer nicht notwendig. In diesem Fall ist es sinnlos.
Wieder einer der nicht richtig C programmieren gelernt hat.

Grüße Uwe

Laut dem Kommentar verhindert das irgendeine Compiler Optimierung. Also hat es theoretisch schon einen Sinn. Aber was genau damit bezweckt werden soll kann man nicht sagen.

Es stellt sich natürlich auch die Frage ob man das Problem nicht auch anders hätte lösen können.

Hallo nochmal,

ich fasse mal zusammen :

Das Goto sollte eigentlich auf den Müllhaufen der IT-Geschichte gelandet sein, jedenfalls in einer Hochsprache.
Wurde mir schon anno 1985 vom Assistenten des Matheprofs untersagt (damals: Pascal) !!!

Das unschöne (unbedingte) goto hier entspricht einfach einer nie endenden Schleife.

Keiner von euch hat das schon mal so gesehen, es ist also nix,was dem erfahrenem Arduino'er bekannt vorkommt.

Ich werde mal ein hundsgemeines while testen ...

Danke & Grüße

Harry

Goto ist (fast) immer nicht notwendig. In diesem Fall ist es sinnlos.

Na ja, es "optimiert" natürlich eine µs oder so. Dass das sinnlos ist, stimmt aber auch, schätze ich mal

Warum der Spezialist statt einer Konstruktion wie

void loop() {
  while (1) {
   // Wir killen alles ausserhalb von loop, z.B. serialEvent()
   ...
  }
}

lieber mit goto arbeitet, fragst du ihn am besten selber ...

Ach so, nur um mich zu vergewissern, dass ich es richtig verstanden habe.

loop() wird "irgendwie" ständig vom "Betriebssystem" des Arduino aufgerufen,
ist ein loop() durchgelaufen so wird es wieder neu aufgerufen, bis der Arduino aufgibt :slight_smile: (kein Strom zb) !?

Grüße

Harry

michael_x:
Na ja, es "optimiert" natürlich eine µs oder so. Dass das sinnlos ist, stimmt aber auch, schätze ich mal

Warum der Spezialist statt einer Konstruktion wie

void loop() {

while (1) {
  // Wir killen alles ausserhalb von loop, z.B. serialEvent()
  ...
 }
}



lieber mit goto arbeitet, fragst du ihn am besten selber ...

Das goto lässt halt "ohne Bedingung/Vergleich" an den gedachten Schleifenbeginn springen.
Bei while(1) könnte es sein, dass immer wieder die Bedingung geprüft wird, aber ein cleverer Compiler sollte
eigentlich erkennen dass ein Schleifenabbruch nicht möglich ist und daher auch "assemblertechnisch" einen unbedingten Sprung daraus basteln ...

Anyway, ich wollte allgemein nur wissen, ob das ganz ein mir noch unbekanntes Geheimnis der Arduino-Programmierung enthält und glaube einfach mal : Nein

Danke & Grüße

Harry

Laut Kommentar hat das aber eher was mit avr gcc als der Arduino Software zu tun

Es gibt schon noch ein paar legitime Verwendungen von goto. z.B. Fehlerbehandlung am Ende einer Funktion. Lässt sich mit goto sehr viel schöner lösen als mit anderen Konstrukten. Das ist aber die Ausnahme.

Der Kommentar ist falsch. GCC könnte Loop wegoptimieren. Was verhindert wird ist, daß der Rest des äußeren Loops immer wieder ausgeführt wird. In der Arduino Welt ist das fast immer eine nutzlose Performance Optimierung.

Die Theorie, daß Goto automatisch böse ist halte ich allerdings für zu stark pauschalisierend. Siehe hier: Goto Considered Helpful | Blinkenlight

Die Theorie, daß Goto automatisch böse ist halte ich allerdings für zu stark pauschalisierend.

Pauschal.... (99% Trefferquote)

Wenn in 1% aller Anwendungen ein goto auftaucht, mag es ja gut sein.
Ansonsten gilt: goto ist böse.
Globale Dinge sind böse.
static ist böse.
Andererseits: Ausnahmen bestätigen die Regel.

static ist nicht böse.

Begründung: man muss 6 Buchstaben und ein Leerzeichen extra tippen. In der Zeit (oder schon vorher) überlegt man sich, ob es wirklich erforderlich ist. Wenn ja, ist static genau das was man braucht, wenn --wie beim Arduino-- thread-safe kein Thema ist

Mit einer ähnlichen Begründung kann man eher sagen: "int ist böse", oder zumindest dumm. Das verwendet man nämlich ohne nachzudenken, weil es so schön kurz zu tippen ist.


Was mit einer handgestrickten Dauerschleife ( egal ob per while(1) oder per goto ) sich ändert, ist der Rücksprung und der erneute Aufruf von loop() und alles was dazwischen, ausserhalb von loop, passiert.

Das ist nicht viel, so dass man nicht viel gewinnt. Ausserdem müsste man wissen, was es ist ( jetzt und in zukünftigen Arduino Versionen ) um abschätzen zu können ob es sich lohnt.

Mal eben geguckt:
ArduinoCore-samd/main.cpp at master · arduino/ArduinoCore-samd · GitHub :

...
  setup();

  for (;;)
  {
    loop();
    if (serialEventRun) serialEventRun();
  }

Ich denke mal, wenn's für ein Theremin darauf ankommen sollte (wie wird der Ton erzeugt ?), vermutlich gleich die Arduino-Komfortumgebung weglassen und nanosekunden schinden

michael_x:
Was mit einer handgestrickten Dauerschleife ( egal ob per while(1) oder per goto ) sich ändert, ist der Rücksprung und der erneute Aufruf von loop() und alles was dazwischen, ausserhalb von loop, passiert.
Mal eben geguckt: ArduinoCore-samd/cores/arduino/main.cpp at master · arduino/ArduinoCore-samd · GitHub :

...

setup();

for (;:wink:
 {
   loop();
   if (serialEventRun) serialEventRun();
 }



Ich denke mal, wenn's für ein Theremin darauf ankommen sollte (wie wird der Ton erzeugt ?), vermutlich gleich die Arduino-Komfortumgebung weglassen und nanosekunden schinden

Hi,

toll dass ihr euch so viele Gedanken macht, da lernt man (ich!) nebenher noch was.

Tja, wie der Ton erzeugt wird ist mir noch nicht 100% klar, im Grunde wird eine Wavetable (also ein int-Array) ausgelesen
und zum richtigen Zeitpunkt der richtige Wert an den DAC geschickt. Ist natürlich schon irgendwie zeitkritisch.

Aber nicht so, dass man mit goto wirklich was rausholen könnte. Interessanter ist, dass man durch die Schleife im loop die Serialabfrage ausserhalb des loop vermeidet, denn da wird es kein Event geben, daher hat man ein paar µ/nano-Sekunden eingespart.

Werden beim Arduino eigentlich lokale Variablen auf dem Stack abgelegt ?

Viele Grüße

Harry

PS.: Ich werde im loop() statt goto mal die for-Variante (wie oben) verwenden, die ist ja sozusagen Tüv-geprüft :slight_smile:

Werden beim Arduino eigentlich lokale Variablen auf dem Stack abgelegt ?

Ja.
In den 2kB RAM eines Uno haben globale und statische Variable, Heap und Stack locker Platz :wink:

static ist nicht böse.

:slight_smile: Nur ein weg gelassenes static ist ein gutes static :slight_smile:

Ich sage ja nichts gegen einen sinnvollen Einsatz.
So ist es beim Goto ja auch.....

Aber bedenke:

Wer einmal begriffen hat, wie ein Hammer funktioniert, für den sehen alle Probleme plötzlich wie ein Nagel aus.

Eigentlich sollte sich eine Funktion immer gleich verhalten.
Eingabe(Parameter) -> Verarbeitung -> Ausgabe(Returnwert)

Wenn sie statische Variablen beinhaltet, führen die gleichen Eingaben zu unterschiedlichen Ausgaben.
Sie zeigt ein variables Verhalten.
Das verstößt gegen "das Prinzip der geringsten Verwunderung".
Das unterschiedliche Verhalten geht nicht aus der Funktionsdeklaratieon hervor.
Es muss extra dokumentiert werden.
Der Programmierer muss die Doku lesen und verstehen.
Er braucht ein Verständnis über die Interna der Funktion.
Das ist eigentlich nicht erwünscht.

Man sollte sich also in jedem einzelnen Fall klar machen, dass man sich durch die Verwendung von static andere Probleme einhandeln kann.

Ich bezweifle mal generell das der TÜV immer alles richtig macht.
Grüße Uwe

michael_x:
Ja.
In den 2kB RAM eines Uno haben globale und statische Variable, Heap und Stack locker Platz :wink:

Hüstel, da habe ich die Frage wohl zu unspezifisch gestellt. Wenn ich eine lokale Variable einer Funktion auf dem Stack ablege verschwindet sie nach dem exit der Funktion wieder (so kenn ich es aus der "PC-Welt"). Lege ich diese Variable "fest" irgendwo in den Speicher, wäre zb ein rekursiver Aufruf der Funktion unschön, denn ich würde mir die lokalen Variablen überschreiben ...

Grüße

Harry

(so kenn ich es aus der "PC-Welt")

Funktioniert hier genauso

Auch dieses geht in der Arduino IDE:

#include <Arduino.h>

int main() 
{
  while(1)
  {
    // tuwas, ohne unterbrechung
  }
}

Kein setup()
Kein loop()
Keine Unterbrechungen durch den Systemtimer.
Dann tuts allerdings auch kein Millis() (und seine Brüder) mehr.....
Keine Serielle Abhandlung in einer verborgenen Schleife.....

Lege ich diese Variable "fest" irgendwo in den Speicher, wäre zb ein rekursiver Aufruf der Funktion unschön, denn ich würde mir die lokalen Variablen überschreiben ...

Nicht unschön, sondern so gewollt. Es wäre dann keine lokale Variable, sondern eine static, die den Sinn hat, für alle Rekursionen gemeinsam da zu sein.

static ist wie global, nur vor anderen Funktionen versteckt.

Und damit die 2kRAM auch locker reichen, hält man (ich zumindest) hier Rekursionen für albern.
Das evtl. witzig für Informatik-Studenten, macht aber bei einem Microcontroller nicht wirklich Sinn.