Der Code funktioniert, nur die Meldungen nerven.
Gibt es eine Abhilfe, ohne die dangling-pointer Warnung ganz abzuschalten?
Warum ist taskLableStart keine lokale Variable (wirft keine Warnung) aber die anderen schon?
Ich sehe da keinen Unterschied.
taskLableStart ist auch nicht von außen erreichbar.
Selbst wenn ich beide Vorkommen in taskLableStart4711 ändere, keine Meldung und funktioniert wie gewollt.
Die Zahlen sind es nicht, die mir Sorgen machen.
Aber für mich ist ein Label ein Label und keine lokale Variable.
beantwortet sein. Mit der GCC-Erweiterung ist ein Label ein Wert, der einer Variablen vom Typ "void *" zugewiesen werden kann.
Genau das wird im Code mehrfach gemacht. Ein Label wird mit dem &&-Operator geholt und der Variable "label" zugewiesen.
Aber, und da hat der Compiler recht, die Scopes der Label (also Werte) taskLabel39, taskLabel44 und taskLabel47 sind im (unterhalb des) Scope der Variable "label" verschachtelt. Und zwar 2 (39) bzw. 3 Ebenen (44, 47) tiefer (wenn ich mich nicht verzählt habe).
Die "Labels as Values" werden nach oben in einem Scope gespeichert wo sie nach Meinung des Compilers (und ich glaube zurecht) nicht immer gültig sind.
Der Task-Switching Code springt über die Dangling Pointer in tiefer liegende Scopes ein, und niemand weiß wie der Stack zu dem Zeitpunkt für die Scopes aussieht. Dass das funktioniert ist Glück.
In der verlinkten Beschreibung steht auch drin (erster Satz):
You can get the address of a label defined in the current function
(or a containing function)
D.h. in andere Richtung geht es. In einem nested Scope den Wert eines Labes in einem umgebenden, höheren Scope darf man holen und benutzen - um damit aus einem umgebenden Scope wieder nach oben zu springen. Bei deinem Code wird aber nicht nach oben gesprungen, sondern nach unten oder seitwärts.
(unten, oben, seitwärts im Sinne der Verschachtelung der Scopes, nicht der Programmzeilen).
taskLableStart ist auch nicht von außen erreichbar.
Nein, aber wird im gleichen Scope zugewiesen und benutzt, in dem "label" deklariert ist. Damit ist der Pointer in dem Scope gültig und wird nicht angemeckert.
Noch ein Zitat aus der Beschreibung
You may not use this mechanism to jump to code in a different function.
If you do that, totally unpredictable things happen. The best way to
avoid this is to store the label address only in automatic variables
and never pass it as an argument.
Mein Fazit, der Code ist Scheiße und reine Glückssache dass das funktioniert.
Wie kommt man eigentlich auf solch einen Mist? Du arbeitet hier auf einem potenten CM4 und murkst mit so einem Protothreads ähnlichen Zeug rum? Wenn schon kooperatives Multitasking dann wenigstens über vernünftige Statemachines.
Die Protothreads sind doch keine Arduino Erfindung, die gibt es schon lange und andere benutzen die auch.
Ist das eine selbst modifizierte Variante? Ich sehe auch nicht das die lableTaskXX verschachtelt sind, die sind im Scope von lable. Aber warum ist lable static? Kann das das Problem sein? Der static Pointer wäre doch ungültig wenn er auf Stackvariablen zeigt.
Und wer hat das 'lable' genannt?
Vielleicht jemand, der meint, daß es britischer klingt, wenn man die E-Konsonant-Kombination am Wortende durch Konsonant-E ersetzt, wie es in "Centre" und "Theatre" geschieht, (statt des amerikanischen "Center" und "Theater").
Wäre es global, könnte es nur eine Task geben. Oder eben für jede Task eine globale mit eigenem Bezeichner
Die Funktion test() wird auf dem STM32 ein paar Millionen mal pro Sekunde aufgerufen.
Über all die Aufrufe muss das Sprungziel gemerkt werden.
Also darum: static.
In meinem original Code ist es eine Instanzeigenschaft (nicht static), dort bin ich auf die Meldungen gestoßen.
Das oben gezeigte Beispiel ist eine Minimal Version um die Meldung zu reproduzieren.
Dieses Beispiel hier wirft die Meldung berechtigt:
1
int*merker;
2
3
voidsetup()
4
{
5
inttest=42;
6
7
Serial.begin(9600);
8
merker=&test;
9
}
10
11
voidloop()
12
{
13
Serial.println(*merker);
14
}
Es wirft:
warning: storing the address of local variable 'test' in 'merker' [-Wdangling-pointer=]
Logisch, die lokale Variable verfällt nach dem verlassen der Funktion setup(), und der pointer ist "dangling".
Da ist die Meldung korrekt!
Das Beispiel im Eingangsposting hat keine verfallenden Variablen. Nirgendwo.
Aber für mich ist ein Label ein Label und keine lokale Variable.
beantwortet sein. Mit der GCC-Erweiterung ist ein Label ein Wert, der
einer Variablen vom Typ "void *" zugewiesen werden kann.
Deiner Logik kann ich nicht folgen. Der void Zeiger wird nicht angemeckert.
Sondern die angebliche Variable namens "taskLable39"
Der verlinkte Text ist mir natürlich bekannt.
Mit keiner einzigen Zeile verstoße ich gegen die dort genannten Bedingungen.
Oder habe ich da was übersehen?
Ja!
Das Original von Adam Dunkels verwendet switch/case als Mechanismus. Was es schwieriger macht switch/case dann noch selber in der Task nutzen zu wollen.
Zudem mutiert switch bei zunehmender Anzahl case von einer Sprungleiste zu einer Kette von Vergleichen, welche es sehr langsam macht, ins Besondere für die weit hinten liegenden Fälle.
Die goto Variante ist immer gleich schnell.
Wie kommt man eigentlich auf solch einen Mist? Du arbeitet hier auf
einem potenten CM4 und murkst mit so einem Protothreads ähnlichen Zeug
rum? Wenn schon kooperatives Multitasking dann wenigstens über
vernünftige Statemachines.
Es ist eine Statemachine.
Das Verfahren funktioniert.
Mein Ziel ist es, es auf allen Arduino üblichen Plattformen (ohne Meldung) zum laufen zu bekommen.
Bisher läuft es vom Tiny85(alle 8Bit AVR) über alle ESP bis gar zum K210 mit seinen 64Bit.
You may not use this mechanism to jump to code in a different function.
If you do that, totally unpredictable things happen. The best way to
avoid this is to store the label address only in automatic variables
and never pass it as an argument.
Das trifft auf meinen Code nicht zu, bleibt alles in der gleichen Funktion.
Vermutung: Der Compiler behandelt die labels wie lokale Variablen (was deren Lebensdauer betrifft). Das erklärt dann die Warnungen, und auch, warum es bei taskLableStart nicht auftritt.
Der Compiler behandelt die labels wie lokale Variablen
Ja!
Die Frage ist, warum tut er das?
Denn es ist ja ein Label und keine Variable.
Oder viel wichtiger, wie kann ich im das abgewöhnen, das Label als Variable zu betrachten?
Die "Labels as Values" werden nach oben in einem Scope gespeichert wo
sie nach Meinung des Compilers (und ich glaube zurecht) nicht immer
gültig sind.
Der Task-Switching Code springt über die Dangling Pointer in tiefer
liegende Scopes ein, und niemand weiß wie der Stack zu dem Zeitpunkt für
die Scopes aussieht. Dass das funktioniert ist Glück.
Das ist natürlich richtig.
Zumindest das mit den Anweisungsblöcken, da springe "ich" in tiefere Ebenen.
Aber das mit dem Stack, das ist irrelevant.
Da ist nix mit Stacknutzung!
Damit ist:
nicht immer gültig sind.
falsch
Und auch:
und niemand weiß wie der Stack zu dem Zeitpunkt für
die Scopes aussieht. Dass das funktioniert ist Glück.
Die Warnungen abzuschalten dürfte ja kein allzu großes Problem sein,
oder?
Doch!
disable GCC warnings for a few lines of code
Ist in diesem Fall keine Lösung.
Es hat in einer Zeile zu geschehen.
Eine eher globale Abschaltung ist natürlich möglich, aber auch nicht so sinnvoll, da in der Luft hängende Pointer durchaus gefährlich werden können/sind.
Das Verfahren funktioniert.
Mein Ziel ist es, es auf allen Arduino üblichen Plattformen (ohne
Meldung) zum laufen zu bekommen.
Bisher läuft es vom Tiny85(alle 8Bit AVR) über alle ESP bis gar zum K210
mit seinen 64Bit.
Dein Verfahren funktioniert nicht oder zumindest nur für Spielzeuganwendungen. Schreibst du sogar selbst:
Zudem mutiert switch bei zunehmender Anzahl case von einer Sprungleiste
zu einer Kette von Vergleichen, welche es sehr langsam macht, ins
Besondere für die weit hinten liegenden Fälle.
Das ist im allgemeinen so Unsinn. Es kommt auf den Compiler an.
Wieso verwendest Du Compilerspezifika, wenn du willst, das es auf möglichst vielen Platformen läuft? Das ist genau das Gegenteil von dem was man da macht.
werden Labels wohl intern etwas anders behandelt. Anscheinend hat sich das mit Version 13 auch wieder geändert, zumindest ist die Warnung weg. Im Kontext von C++ solltest Du Dir auch über andere Folgen im Klaren sein.
Zudem mutiert switch bei zunehmender Anzahl case von einer Sprungleiste
zu einer Kette von Vergleichen
Die Entscheidungsfindung der Implementierung eines Switch-Statesments ist weit komplexer. Eine Variante der Kette aus Vergleichen ist ein Binärbaum an Stelle linearer Vergleiche. Bei vielen und weit auseinander liegenden Fällen ist so ein Entscheidungsbaum im Platzverbrauch effizienter als eine Tabelle. Weshalb das Optimierungsziel Tempo/Platz eine Rolle spielen kann.
Wenn ein Update aus irgendeinem Grund nicht möglich sein sollte:
Compiler-Warnungen sind Hinweise auf /mögliche/ Fehler. Wenn du sicher
bist, alles richtig gemacht zu haben, und dich die Warnung stört, kannst
du sie ja auch einfach abschalten.
Wieso verwendest Du Compilerspezifika, wenn du willst, das es auf
möglichst vielen Platformen läuft? Das ist genau das Gegenteil von dem
was man da macht.
In der Arduinowelt kommt bisher ausschließlich der Gcc zu Einsatz.
Dein Verfahren funktioniert nicht oder zumindest nur für
Spielzeuganwendungen. Schreibst du sogar selbst:
Arduino F. schrieb:
Irrelevant, da keine Stacknutzung.
In dem Beispiel findet keine Stacknutzung statt, die mit dem Pointer/Warnung in Verbindung steht.
Natürlich nutzt das dort verwendete Serial.println() den Stack. Was aber kein Problem darstellt. Der Stack ist ja da und nutzbar.
Meinen herzlichen Dank für die freundliche Unterstützung.
Mit eurer Hilfe und noch ein bisschen Doku stöbern konnte ich mein Problemchen lösen.
Es funktioniert wie geplant, und die Meldungen unterbleiben.
Es funktioniert wie geplant, und die Meldungen unterbleiben.
Für die typische Arduino-Definition von "funktioniert". Du springst immer noch in Bereiche ein ohne den Stack richtig zu handhaben. Und Register auch nicht.
Du hast ein triviales Beispiel dass zufällig funktioniert. Das ist alles.
Der Code funktioniert, nur die Meldungen nerven.
Du kannst deine Behauptung noch so oft wiederholen, der Code funktioniert nicht. Hat vorher nicht funktioniert und wird durch Abschalten der Warnung auch nicht funktionieren.