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 ?
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.
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.
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 (kein Strom zb) !?
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
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.
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.
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.
...
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
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
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
Nur ein weg gelassenes static ist ein gutes static
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.
michael_x:
Ja.
In den 2kB RAM eines Uno haben globale und statische Variable, Heap und Stack locker Platz
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 ...
#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.