Johann L. schrieb: > Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog. > > Phase 1: Watchdog wird konfiguriert und aktiviert. > > Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen > Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder > zumindest mehrere µs dauern. Und wann macht das Ding dann etwas? Immer nur zwischen Phase 1 und 2? > Beispiel 2: Eine Applikation, die all ihre Aufgaben in ISRs erledigt. Am > Ende von main, nach Konfiguration aller IRQs, steht dann eine leere > Endlosschleife. Das muss man aber so nicht machen. Mann kann das auch anders lösen. Deswegen ist das kein Argument.
Wilhelm M. schrieb: > Und wann macht das Ding dann etwas? Immer nur zwischen Phase 1 und 2? Es geht darum, gezielt einen Hardware-Reset auszulösen auf Plattformen, die das nicht direkt können (bpsw. AVR). Nachdem man den Wachhund gezündet hat, soll natürlich einfach mal nichts mehr passieren, bis er dann zuschlägt. Das "nichts mehr" macht man in einer harten Endlosschleife. Anderer realer Fall: MCU im Fehlerfall (bspw. bei einem abort()) anhalten. Wenn man mit dem Debugger dran sitzt, kann man dann an der Stelle unterbrechen und versuchen nachzuvollziehen, wie es zum Fehler gekommen ist. Auch das braucht einfach eine harte Endlosschleife. Ähnlich, wenn man auf einer MCU aus main() zurückkehrt.
Wilhelm M. schrieb: > Johann L. schrieb: >> Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog. >> >> Phase 1: Watchdog wird konfiguriert und aktiviert. >> >> Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen >> Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder >> zumindest mehrere µs dauern. > > Und wann macht das Ding dann etwas? In Phase 1 macht es etwas: Initialisierung etc. In Phase 2 macht es etwas: JMP auf sich selbst bis die Zeit zum Watchdog-Reset verstrichen ist. Falls du nicht weißt was'n Watchdog ist: https://de.wikipedia.org/wiki/Watchdog >> Beispiel 2: Eine Applikation, die all ihre Aufgaben in ISRs erledigt. Am >> Ende von main, nach Konfiguration aller IRQs, steht dann eine leere >> Endlosschleife. > > Das muss man aber so nicht machen. Na das ist man ein Argument. Bravo!
Jörg W. schrieb: > Wilhelm M. schrieb: >> Und wann macht das Ding dann etwas? Immer nur zwischen Phase 1 und 2? > > Es geht darum, gezielt einen Hardware-Reset auszulösen auf Plattformen, > die das nicht direkt können (bpsw. AVR). Nachdem man den Wachhund > gezündet hat, soll natürlich einfach mal nichts mehr passieren, bis er > dann zuschlägt. Das "nichts mehr" macht man in einer harten > Endlosschleife. Mir ist schon klar, was ein WatchDog erreichen soll. Nur wo "sitzt" in dem Beispiel die Applikation? > Anderer realer Fall: MCU im Fehlerfall (bspw. bei einem abort()) > anhalten. Wenn man mit dem Debugger dran sitzt, kann man dann an der > Stelle unterbrechen und versuchen nachzuvollziehen, wie es zum Fehler > gekommen ist. Auch das braucht einfach eine harte Endlosschleife. > Ähnlich, wenn man auf einer MCU aus main() zurückkehrt. In diesem Fall kommt es aber so gar nicht darauf an, mit welcher Frequenz die Loop durchlaufen wird. Ggf. wird man darin eh irgend etwas tun, ggf. sogar ein Pin wackeln. Also hier muss man kein UB haben. Deswegen ist das auch kein Argument.
Jörg W. schrieb: > Thread hier befasst sich ja nun auch an vielen Stellen > mit (Un-)Schönheiten von C als solches. Hoffentlich nicht fruchtlos.
Johann L. schrieb: > Wilhelm M. schrieb: >> Johann L. schrieb: >>> Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog. >>> >>> Phase 1: Watchdog wird konfiguriert und aktiviert. >>> >>> Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen >>> Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder >>> zumindest mehrere µs dauern. >> >> Und wann macht das Ding dann etwas? > > In Phase 1 macht es etwas: Initialisierung etc. > > In Phase 2 macht es etwas: JMP auf sich selbst bis die Zeit zum > Watchdog-Reset verstrichen ist. Wenn das Ding nur auf den WatchDog wartet, ohne da jemals eine LED angeht, dann kann ich auch einfach einen ohmschen Widerstand nehmen, um den Strom zu verbrauchen. >>> Beispiel 2: Eine Applikation, die all ihre Aufgaben in ISRs erledigt. Am >>> Ende von main, nach Konfiguration aller IRQs, steht dann eine leere >>> Endlosschleife. >> >> Das muss man aber so nicht machen. > > Na das ist man ein Argument. Bravo! Du stehst also auf dem Standpunkt: ich WILL aber unbedingt so eine Endlos-Schleife in C++, und ich weiß aber, dass das UB ist, und ich WILL aber, das es trotzdem geht. Mmh, hört sich an wie Vorschulalter ...
Wilhelm M. schrieb: > Johann L. schrieb: >> Wilhelm M. schrieb: >>> Johann L. schrieb: >>>> Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog. >>>> >>>> Phase 1: Watchdog wird konfiguriert und aktiviert. >>>> >>>> Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen >>>> Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder >>>> zumindest mehrere µs dauern. >>> >>> Und wann macht das Ding dann etwas? >> >> In Phase 1 macht es etwas: Initialisierung etc. >> >> In Phase 2 macht es etwas: JMP auf sich selbst bis die Zeit zum >> Watchdog-Reset verstrichen ist. > > Wenn das Ding nur auf den WatchDog wartet, ohne da jemals eine LED > angeht, dann kann ich auch einfach einen ohmschen Widerstand nehmen, um > den Strom zu verbrauchen. Ach komm, gib dich mal nicht dümmer als du bist. Du verstehst doch sehr wohl wozu das gut ist. Und ja, die Applikation macht mehr als nur einen Reset. Der Reset wird nur bei bestimmten Vorbedingungen gebraucht. Denkbare Anwendung wäre ein Bootloader, der nach Aktualisiserung der Anwendung diese anspringt. Ein Hardware-Reset resettet die ganze Hardware, was hier gewünscht ist. > so eine Endlos-Schleife in C++, und ich weiß aber, dass das UB ist, > und ich WILL aber, das es trotzdem geht. Ja. Weil in neueren C++ Versionsn for(;;); UB ist, möchte ich wissen, welches Konstrukt der empfohlene, portable Weg ist, was alte Verhalten zu erreichen. Ist das so viel verlangt?
Johann L. schrieb: > Ja. Weil in neueren C++ Versionsn for(;;); UB ist, möchte ich wissen, > welches Konstrukt der empfohlene, portable Weg ist, was alte Verhalten Das war <= C++03 (vor 20 Jahren) > zu erreichen. Nochmal: for(;;){} ist UB. Punkt. > Ist das so viel verlangt? Das habe ich nun schon x-mal geschrieben, welche Alternativen zur Verfügung stehen. Und das sind dann welche, die die Latenz für die ISR gar nicht beeinflussen. Daher: nimm sie, oder lass es sein.
:
Bearbeitet durch User
Wilhelm M. schrieb: > Johann L. schrieb: >> Ja. Weil in neueren C++ Versionsn for(;;); UB ist, möchte ich wissen, >> welches Konstrukt der empfohlene, portable Weg ist, was alte Verhalten > > Das war <= C++03 (vor 20 Jahren) > >> zu erreichen. > > Nochmal: for(;;){} ist UB. Punkt. Klar. Und genau deshalb frage ich ja nach einem ERSATZ. > Das habe ich nun schon x-mal geschrieben, welche Alternativen zur > Verfügung stehen. Bisher habe ich zumindest in diesem Thread von dir keine einzige Alternative gefunden. Wortreiche Umschreibungen und Characterisierungen ja, aber wie lautet denn nun der magische Code?
Hallo, ich muss zugeben mir ergeht es aktuell wir Gerhard. Der Thread hat mich vollkommen durcheinander gebracht. Gewohnte Fachbegriffe haben hier eine andere Bedeutung erlangt. Ich komme einfach nicht mehr mit. Ich gebe es auf. Ich programmiere weiter wie immer und hoffe das alles funktioniert. Ich muss mich darauf verlassen das der gcc keinen ungewohnten Mist macht. Ich danke allen die Antworten auf meine Fragen gegeben haben, auch wenn ich diese im Zusammenhang hier nur noch teilweise verstehe und einsortieren kann. Weitere Nachfragen würden in einer weiteren nebenläufigen Endlosschleife enden. Das möchte ich niemanden zumuten. Ich melde mich aus dem Thread ab.
Johann L. schrieb: > Bisher habe ich zumindest in diesem Thread von dir keine einzige > Alternative gefunden. Wortreiche Umschreibungen und Characterisierungen > ja, aber wie lautet denn nun der magische Code? z.B.: Beitrag "Re: for(;;){} Schleife" oder Beitrag "Re: for(;;){} Schleife"
Wilhelm M. schrieb: > Johann L. schrieb: >> Bisher habe ich zumindest in diesem Thread von dir keine einzige >> Alternative gefunden. Wortreiche Umschreibungen und Characterisierungen >> ja, aber wie lautet denn nun der magische Code? > > z.B.: > > Beitrag "Re: for(;;){} Schleife" > > oder > > Beitrag "Re: for(;;){} Schleife" C++ definiert sleep() und noop() ? Nicht-portable Lösungen sind ja naheliegend, wie __asm volatile ("":); für g++. Aber das ist offenschtlich NICHT portabel.
Johann L. schrieb: > Wilhelm M. schrieb: >> Johann L. schrieb: >>> Bisher habe ich zumindest in diesem Thread von dir keine einzige >>> Alternative gefunden. Wortreiche Umschreibungen und Characterisierungen >>> ja, aber wie lautet denn nun der magische Code? >> >> z.B.: >> >> Beitrag "Re: for(;;){} Schleife" >> >> oder >> >> Beitrag "Re: for(;;){} Schleife" > > C++ definiert sleep() und noop() ? Das spielt schon in dem Moment keine Rolle mehr, wo Du ISRs einsetzt. Denn die sind auch nicht konform. > > Nicht-portable Lösungen sind ja naheliegend, wie __asm volatile ("":); > für g++. > > Aber das ist offenschtlich NICHT portabel. Du argumentierst doch im Kreis: einerseits willst Du ISRs oder Exception-Handler oder WDT einsetzen, die nicht portabel sind, und andererseits beschwerst Du Dich über sleep() und noop(), was nicht portabel sei? Wenn Du komplett auf nicht-potable Sachen wie ISRs, sleep(), noop(), etc. verzichtest, dann hast Du ein Programm ohne sichtbaren Effekt. Das ist sinnlos, und nichts anderes sagt diese Regel aus C++.
Beitrag #7485073 wurde vom Autor gelöscht.
Wie gesagt, eine leere Endlosschleife (natürlich ein nicht-UB Ersatz dafür) KANN sinnvoll sein, egal ober der Rest des Codes ISRs oder was auch immer verwendet oder nicht. Nach deiner Lesart sind ISRs nicht sprachkonform, und daher kann Code, der ISRs verwendet, beliebige nicht-konfirme Konstrukte verwenden. Ich denke auch nicht, dass du noch mit einer Lösung um die Ecke kommst.
Johann L. schrieb: > Wie gesagt, eine leere Endlosschleife (natürlich ein nicht-UB Ersatz > dafür) KANN sinnvoll sein, egal ober der Rest des Codes ISRs oder was > auch immer verwendet oder nicht. Beispiel? Und - um Deine Worte zu gebrauchen - keine wortreichen Umschreibungen. > Nach deiner Lesart sind ISRs nicht sprachkonform, und daher kann Code, > der ISRs verwendet, beliebige nicht-konfirme Konstrukte verwenden. Tut er bereits durch die ISRs. Daher darfst Du ruhig Dein asm("") einsetzen, das zwar implementation-defined ist, aber auf wohl den meisten Compilers tut. > Ich denke auch nicht, dass du noch mit einer Lösung um die Ecke kommst. Die verlinkte noop() Variante ist komplett konform (man könnte auf das eine Byte auch noch verzichten).
Wilhelm M. schrieb: > Johann L. schrieb: >> Nach deiner Lesart sind ISRs nicht sprachkonform, und daher kann Code, >> der ISRs verwendet, beliebige nicht-konfirme Konstrukte verwenden. > > Tut er bereits durch die ISRs. Der Unterschied ist aber, dass die für ISRs erforderlichen Mittel von der Implementation zur Verfügung gestellt und garantiert werden. Von daher sind das alles Strohmann-Nebelkerzen deinerseits. > Die verlinkte noop() Variante ist komplett konform (man könnte auf das > eine Byte auch noch verzichten). Ok hatte die Definition übersehen. Wobei es hier auch schon mal ne ewige endlos-Diskussion darüber gab, ob (void) var; for eine volatile Variable noch den neueren Standards entsprechen die auch an volatile rumgeschraubt haben. Und wie man das 1 Byte einsparen könnte, sehe ich auch nicht.
Johann L. schrieb: > Wilhelm M. schrieb: >> Johann L. schrieb: >>> Nach deiner Lesart sind ISRs nicht sprachkonform, und daher kann Code, >>> der ISRs verwendet, beliebige nicht-konfirme Konstrukte verwenden. >> >> Tut er bereits durch die ISRs. > > Der Unterschied ist aber, dass die für ISRs erforderlichen Mittel von > der Implementation zur Verfügung gestellt und garantiert werden. Dann kannst Du genau diese "Mittel" auch in der trivialen Endlos-Loop verwenden, also z.B. asm("") der Implementierung. > Von daher sind das alles Strohmann-Nebelkerzen deinerseits. Nein, ich habe Dir das jetzt mehrmals schlüssig dargelegt. Wie gesagt: Wilhelm M. schrieb: > Du stehst also auf dem Standpunkt: ich WILL aber unbedingt so eine > Endlos-Schleife in C++, und ich weiß aber, dass das UB ist, und ich WILL > aber, das es trotzdem geht. Mmh, hört sich an wie Vorschulalter ... >> Die verlinkte noop() Variante ist komplett konform (man könnte auf das >> eine Byte auch noch verzichten). > > Ok hatte die Definition übersehen. Also, erst lesen, dann meckern. > Wobei es hier auch schon mal ne ewige endlos-Diskussion darüber gab, ob > (void) var; for eine volatile Variable noch den neueren Standards > entsprechen die auch an volatile rumgeschraubt haben. Es gibt nur die Warnung (gcc), dass die Variable tatsächlich nicht benutzt wurde. Das ist auch gut so. Denn wäre dass ein SFR, wäre es bestimmt ein Fehler. > Und wie man das 1 Byte einsparen könnte, sehe ich auch nicht. Ich gehe davon aus, das der fragliche Code sicher irgendwo (lokal in main, global, ...) ein beliebiges Objekt definiert, was man volatile-referenzieren kann.
Diese Thread hat sich echt interessant entwickelt. Danke für die vielen Aspekte. Die Beispiele von Johann hatte ich schon öfters in realem Code. Eure Diskussion aktuell geht aber meiner Meinung nach am wesentlichen vorbei: Vielen Entwicklern – nicht nur Anfängern – sind die Konstrukte, die Undefined Behavior erzeugen nicht bewusst, sei es, dass sie sich nie damit beschäftigt haben, sei es, dass sie es vergessen haben. Ich habe mit Softwareentwicklern mal ein Quiz veranstaltet. Es war erschreckend wie viele Programmierer UB Fälle nicht erkannt haben. Wenn C++(03) eine for(;;); Schleife wegen UB rausoptimiert, ohne eine Warnung zu generieren, ist das die schlechteste Vorgehensweise. Gerade dann, wenn es "ähnlichen" C Code gibt, der so etwas nicht raus optimiert. Es gilt eigentlich die Goldene Regel: Kenne Deine Werkzeuge! Die Praxis zeigt: der Mensch macht Fehler, ist vergesslich und macht Annahmen, die nicht stimmen. In diesem Kontext sollte ein Compiler eigentlich auf UB hinweisen. Tut er hier nicht, und das ist IMHO ein Problem. Warum C++03 damals die Schleife als UB angesehen hat, hat mich immer gewundert. Wenn die (embedded) Praxis viele Beispiele hat, macht es keinen Sinn das Verhalten zu ändern.
Moin, Ich finde diese UB Möglichkeiten und Unsicherheiten nicht gerade sehr erbauend. Ich kann nicht beurteilen, inwiefern moderne Tools anderer Produkte sich daranhalten, die sich an die neuesten Standards halten. Fakt ist, daß alle meine älteren Tools dieses speziell aufgebrachten Problem nicht haben und diese Konstrukte, wie traditionell erwartet, richtig funktionieren. Abgesehen davon, merkt man ja beim Testen sofort, ob der Compiler sich solche Freiheiten erlaubt hat. Man gewinnt ja über die Jahre hinaus viele Erfahrungen mit den Werkzeugen mit denen man zu tun hat und kennt die besonderen Probleme und vermeidet die "bösen" Konstrukte. Ich befasse mich auch mit einigen anderen uC anderer Hersteller und die Werkzeuge sind auch nicht mehr die Jüngsten. Jedenfalls wären mir diese "Freiheiten" schon längst beim Testen aufgefallen. Noch nie hatte ich mit den hier diskutierten Schleifenkonstrukten jemals ein Problem und mir hat noch kein Compiler eine Test Watchdog Trigger Endlosschleife wegoptimiert. Das wäre beim Testen sofort aufgefallen. Inwieweit UB ein praktisches Problem ist oder eher ein Akademisches, kann ich nicht wirklich beurteilen. Ausschlaggebend für mich ist, daß die Sprache anhand der bereitgestellten Dokus, so wie dort beschrieben, richtig funktioniert. Früher schien das zu genügen um produktiv in der Praxis wirken und bestehen zu können. Wie ist es in der UNI? Lernt man dort hauptsächlich die Sprachen und deren Anwendung, oder studiert man extensiv Compiler Standard Dokus? Sicher, ab und zu muß man sie bei der Fehlersuche konsultieren, aber das sollte nur selten notwendig sein. Hätte es wirklich viel Sinn, alle diese Compiler Standard Schrulligkeiten lernen und im Kopf behalten zu müssen? Ich glaube, nein. Es kommt halt letzen Endes darauf an, wie zuverlässig das Gesamtprodukt sein muß, um diese Unsicherheiten überprüfen zu wollen. Letzten Endes kommt es auf ausreichend gutes und komplettes Testen der Anwendung an. Letztlich bin ich also der Meinung, daß Eure ganze Diskussion fast vollkommen akademisch ist und in der Praxis nur unter besonderen Umständen Gewicht hat, wenn man genug Praxis Erfahrung mit den Werkzeugen hat. Das größte Problem mit C++ ist, daß es viel zu komplex und "fancy" geworden ist und dieser Trend fortgehend weitergeht. Viele Eigenschaften sind so implizit und versteckt, daß nur noch ein ausgedehntes Studium darüber Klarheit beschafft. In klassischen C, da nur ein Mittelding zwischen ASM und Hochsprachen sein wollte, waren viel klarere Verhältnisse. Der Trouble mit C++ ist, daß man es heute als "Mädchen für alles" hochgezogen hat und derart komplex geworden ist, daß nur noch hartgesottene Spezialisten, die täglich ihr Brot damit verdienen, sich damit ausreichend auskennen. Zum gelegentlichen Programmieren sollte man die esoterischen Besonderheiten der Sprache, meiner Meinung nach eher vermeiden wenn sie nicht ausdrücklich extrem nützlich sind, und lieber mit Grundfunktionalität jonglieren. Mir ist aufgefallen, daß ältere traditionelle Sprachen großteils aus ihrem Syntax verständlich waren. Eine Fortran oder Pascal Quelle konnte man mit wenig Recherche verstehen, die heutigen Sprachen sind ohne Studium fast vollkommen unverständlich. Der Syntax gibt beim Lesen nicht länger Aufschluss auf die gemeinte Funktionalität. Nur ausführliches Wissen dieser Konstrukte und zugängliche Referenzdokumentation gibt noch Aufschluss. Das ist der Preis des Fortschritts, vermute uch. Aus meiner Sicht machte ich die Erfahrung, daß ich C Code meist total verständlich finde, bei C++ andauernd nachschlagen muß was im Einzeln gemeint ist und die Terminologie nicht unbedingt immer ausreichend verständlich ist. Ja, Klassen und Objekte können ja recht nützlich und bequem sein. Aber für viele embedded Anwendungen mit Ressourcen begrenzten uC eigentlich doch nicht wirklich notwendig. Bei der Fehlersuche kann da schon viel zu viel versteckt sein. Speziell bei fremden Bibliotheken, wo man dann auch jene durchgehen muß. Sind halt meine Ansichten, aber die, viele von Euch wahrscheinlich lächeln werden. Aber nicht jeder steckt in Euren Schuhen. Und da ich mich viel mit HW Design befasse, programmiere ich eben nicht den ganzen Tag, täglich. Es ist ja gut, daß sich jemand (ihr) über UB Gedanken und deren möglichen Auswirkungen macht. Vg, Gerhard
:
Bearbeitet durch User
Klaus H. schrieb: > Warum C++03 damals die Schleife als UB angesehen hat, hat mich immer > gewundert. Kann eigentlich nicht sein, denn diese "Formulierung" wurde erst mit C++11 bzw. C11 eingeführt zusammen mit der Definition des Memory-Models. Das Memory-Model wiederum war notwendig, damit gerade die nebenläufigen Konstrukte eine definiterte Semantik bekommen. Diese "Problem", was wir hier diskutieren, ist m.E. die Diskussion um die leere Menge. Denn in der Praxis leben wir mit sehr vielen, nicht-standardisierten Erweiterungen im C++-Compiler (auch im C-Compiler). Schließlich haben wir uns auch daran gewöhnt, nicht standard-konforme ISRs, asm()-Konstrukte, etc. in unseren MCU-Code einzubauen. Deswegen habe ich wiederholt versucht darzustellen, dass das Problem in der Praxis gar nicht existiert. Sei es, weil die leere, triviale Endlos-Schleife ein Spezialfall darstellt, oder Werkzeuge wie GCC ein konsistentes Verhalten im Sinne des least-astonishments zeigen. Trotzdem muss man bei den Sprachen C und C++ das Konzept des UB einfach kennen, denn es ist ein Grundprinzip dieser beiden. Wer das ignoriert, hat schlicht die Sprache nicht verstanden. Und ich möchte nicht wissen, in wie vielen Fällen auch heute noch type-punning via raw-unions in C++ gemacht wird. Das ist zwar ganz klar UB, jedoch wird es im g++ genauso wie im gcc, also im C-Mode behandelt, wo es eben kein UB ist. Das ist auch gut so, verhindert es doch allzugroße Unfälle. Gleichzeitig ist es aber auch schlecht, weil man auf den Fehler nicht hingewiesen wird, solang man keine Analyse-Tools verwendet, was die wenigsten hier wohl machen werden. Daran zeigt sich eben, dass C keine Untermenge von C++ ist, sondern eine eigene Sprache. Deswegen: diese Diskussion hier mag akademisch erscheinen bzw. auch sein, denn - wie gesagt - bin ich der Meinung, dass dies ein Spezialfall ist und wir in der Praxis damit in Reinform gar nicht in Berührung kommen, weil jedes MCU-Programm neben dem Standard liegt. Aber diese Diskussion soll ein Hinweis darauf sein, dass man mit dem Konzept UB umgehen muss: egal, ob Loops, raw-unions, integer-overflow, uninitialized variables, off-object pointer dereference, .....
Wilhelm M. schrieb: > Kann eigentlich nicht sein, denn diese "Formulierung" wurde erst mit > C++11 bzw. C11 eingeführt zusammen mit der Definition des Memory-Models. > Das Memory-Model wiederum war notwendig, damit gerade die nebenläufigen > Konstrukte eine definiterte Semantik bekommen. Ups, sorry. Hast recht. Aber es ändert nichts daran, dass das Konstrukt for(;;); schon Jahre lang im emedded Bereich eingesetzt wurde. Deine Beispiel zeigen ja schön, dass die meisten Compiler es trotzdem wie früher umgesetzt haben. Ich mag clang, aber dieses Verhalten ohne Warnung halte ich für gefährlich. Wenn der Code beim Build jeweils vollständig getestet wird, vielleicht kein Problem. In der Praxis sehe ich aber immer wieder Firmware, die nach dem Motto „wir haben es zwar nicht dokumentiert, aber Entwicklertests wurden gemacht“ getestet wurden. Wilhelm M. schrieb: > Und ich möchte nicht wissen, in wie vielen Fällen auch heute noch > type-punning via raw-unions in C++ gemacht wird Jepp, viel zuviel. Wilhelm M. schrieb: > Aber diese Diskussion soll ein Hinweis darauf sein, dass man mit dem Konzept UB > umgehen muss: egal, ob Loops, raw-unions, integer-overflow, > uninitialized variables, off-object pointer dereference, ..... Volle Zustimmung. Und das Betrifft natürlich C++ und auch C.
Moin, Es würde mich interessieren, welche Berücksichtigungen für den embedded Bereich gemacht werden. Evaluiert der Compiler Quellen für Linux Anwendungen genauso wie für z.B. für den AVR? Inwieweit wird auf die Besonderheiten der uC Rücksicht genommen? Das zu wissen, würde einen gewissen Anhaltspunkt geben. Was mich an diesem Thema stört, ist dass viele Leute einschließlich mich, vor einigen Jahrzehnten mit C Anwendung angefangen haben und die damaligen (kommerziellen) Werkzeuge nur den Sprachengebrauch ohne hintergründige Theorie dokumentierten. Da wurden niemals Konformitätsreferenzen gegeben. Es gab Beispiele und das wars auch. Der Entwickler musste dann eben mit der Zeit seine eigenen Erfahrungen machen. Und, mit Verlaub, jetzt seid ihr da und taucht mächtig in den Morass der UB ein, den nur ein Experte wirklich beurteilen kann. Hat sich Entwicklung nun in 2023 so geändert und hochgeschraubt, daß es ohne Euer (Fach) Wissen in der Praxis nicht mehr geht? Ich will einfach nicht glauben, daß die Ingenieure in den zahlreichen Betrieben in den Anfangsjahren auf Eurem Niveau sein konnten. Abgesehen davon, wer versteht schon gleich die Erklärungen über jedes Detail. Zum Teil verstehe ich da auch nur Bahnhof. Diese Fachsprache zu verstehen ist keine Kleinigkeit. Wo ist da der Mittelweg? Bitte seht es nicht nur von Eurem Standpunkt aus. Es gibt bestimmt noch viele embedded Entwickler die das eher mehr praxisbezogen angehen und auch nicht den Sprachenexpertenfachbezug haben, aber sonst für viele Anwendungen ordentlich programmieren können. Und wo gibt es verständliche Dokus, die etwas breiter verständlich sind? Die Compiler Referenzunterlagen sind leider oft nur schwer verdaulich. Auch im Web, wie z.B. bei Stack Overflow, versteht man auch nicht immer gleich alles. Man bekommt von dieser Diskussion wirklich den Eindruck, wer nicht auf Eurem Niveau ist, in der Industrie nicht mehr die geringste Chance haben zu können. Bitte seht das nicht als persönlichen Angriff bzw. Kritik, aber überm Zaun ist die Welt vielleicht doch etwas diverser. Gerhard
Gerhard O. schrieb: > Inwieweit wird auf die Besonderheiten der uC Rücksicht genommen? Gar nicht, denn der größte Teil der Optimierungen passiert weit oberhalb des Niveaus der konkreten Maschine. Nur so profitieren aber eben auch "tier 3"-Plattformen trotzdem noch von vielen Optimierungen, die vorrangig für die "tier 1"-Plattformen entwickelt und getestet werden.
Gerhard O. schrieb: > Evaluiert der Compiler Quellen für Linux Anwendungen genauso wie für > z.B. für den AVR? Inwieweit wird auf die Besonderheiten der uC Rücksicht > genommen? Jörg W. schrieb: > Gar nicht, denn der größte Teil der Optimierungen passiert weit oberhalb > des Niveaus der konkreten Maschine. Jein, für uC kann man (sollte man? wird man normalerweise?) -ffreestanding angeben. Das gibt es mindestens seit C99. Damit bekommt der Programmierer ein paar Freiheiten (z.B. main, newlib-nano) und muss dafür auf ein paar Optimierungen verzichten, weil es praktisch keine Standard-Bibliotheken gibt: Jörg W. schrieb: > Annahmen hinsichtlich der Funktionalität der Standardbibliothek sind > halt einer der Punkte, der für ein hosted environment zutrifft. > > "Any library facilities available to a freestanding program, other > than the minimal set required by Clause 4, are implementation-defined." > > Prinzipiell könnte es für Funktionen wie strlen() noch machbar sein, > diese bei einem konstanten String zu optimieren (Clause 4 würde das > meiner Meinung nach gestatten), aber in der Praxis passiert es nicht. Bisher wurden in diesem minimal set nur Konstanten definiert und Dinge wie stdarg, die fest im Compiler eingebaut sein müssen. Mit string.h kommen bei C23 zum ersten Mal echte Bibliotheksfunktionen dazu. Bisher musste man für uC-Programme nur den gcc installieren, keine libc. Damit das so bleibt, müsste der gcc die string-Funktionen mitliefern. Es ist ja nicht sicher, ob z.B. die newlib-nano 100% konform ist.
Bauform B. schrieb: >> Gar nicht, denn der größte Teil der Optimierungen passiert weit oberhalb >> des Niveaus der konkreten Maschine. > > Jein, für uC kann man (sollte man? wird man normalerweise?) > -ffreestanding angeben. Wie schon dargelegt, verhindert das allerdings eher Optimierung, als dass es MCU-spezifische Optimierungen aktiviert. Aus ebendiesem Grunde benutze ich es persönlich dafür gar nicht. Die größere "Freiheit", dass ich main() dann auch als "void" deklarieren darf, nützt mir praktisch nichts. Der Rest der üblichen Bibliotheken ist in den Teilen, in denen die Funktionalität des Standards implementiert wird (also der gleiche Namensraum wie vom Standard benannt) recht gut standardkonform, zumindest bei AVR und ARM. (Von der newlib-nano halte ich persönlich nicht so viel, die meisten ARMs sind groß genug, dass sie die Vollversion der newlib problemlos nehmen können.) Bibliotheksfunktionalität, die nicht benutzt wird, kostet ja normalerweise auch nichts.
Oha. Die for-Schleife läuft jetzt schon 15 Tage und wird irgendwie gar nicht mehr verlassen. Da hat wohl jemand die Abbruchbedingung vermurkst.
Bauform B. schrieb: > Jein, für uC kann man (sollte man? wird man normalerweise?) > -ffreestanding angeben. Würde ich nicht machen. Im avr-gcc gibt es zum Beispiel Optimierungen, die NICHT für freestanding gemacht werden. Und das betrifft dann ziemlich jedes Programm, weil es um main geht (das bei freestanding keine Sonderrolle hat).
Johann L. schrieb: > Bauform B. schrieb: >> Jein, für uC kann man (sollte man? wird man normalerweise?) >> -ffreestanding angeben. > > Würde ich nicht machen. Im avr-gcc gibt es zum Beispiel Optimierungen, > die NICHT für freestanding gemacht werden. Ja, tatsächlich freestanding
1 | 20424 24 1952 22400 5780 BUILD/syslib.elf |
2 | 6476 0 716 7192 1c18 BUILD/init.elf |
3 | 2884 0 832 3716 e84 BUILD/gps.elf |
4 | 528 0 0 528 210 BUILD/tzdata.elf |
hosted
1 | 20412 24 1952 22388 5774 BUILD/syslib.elf |
2 | 6460 0 716 7176 1c08 BUILD/init.elf |
3 | 2916 0 832 3748 ea4 BUILD/gps.elf |
4 | 528 0 0 528 210 BUILD/tzdata.elf |
Aber per Definition sind uC-Programme eindeutig freestanding. Konsequenterweise sage ich dem Linker auch noch -nostdlib. Irgendwie war das ganz zu Anfang einfacher und übersichtlicher und jetzt ist es Tradition.
Hab nicht alles gelesen, aber
1 | for(;;){} |
ist einfach wie eine Vokabel - vlt eher noch eine Redewendung in C, die man auswendig lernt. Sie bedarf keiner Verbesserung. Jeder C Programmierer mit etwas Erfahrung kennt das, wieso künstlich irgendwelche Konstrukte erfinden / bauen, die etwas triviales hübscher machen.
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.