Mindestens seit C99 aber schon.
Nö.
doch.
|
Anzeige
|
for(;;){} Schleife
doch.
Gast
#7478638
Ich hau mich weg, das steht "removed in C23". Und "Bequemlichkeits-Makro", die reinste Warmduscherei ...
Freut mich, dass du dich auch über kleine Dinge amüsieren kannst.
Richtig, dafür ist es ab C23 ein eigener Typ.
Gast
#7478647
Über den Unterschied zwischen "Weg Hauen" und "Amüsement" müsste man sich mal in Ruhe unterhalten ... Ich finde es jedenfalls nicht hilfreich, das hier die Benutzung von "abgeschnittenen Sonderlocken" aus Gründen der Bequemlichkeit vorgeschlagen wird.
Kann es sein, dass es an deinem Leseverständnis hapert?
Gast
#7478659
Alter Falter, nicht mal Jahreszahlen kriegt man hier richtig gebacken ... Ja klar, in irgendeinem Standard von anno "AchHatDerHundDieEckeMitDerJahreszahlGefressen" steht es so oder doch anders und warum schreibt man überhaupt "Standards" wenn man diese wie politische Parteien je nach Wahlkampf umfrisiert ... Geburtsfehler ist nun mal Geburtsfehler, da kann auch plastische Chirurgie nur den Anschein aufhübschen aber nicht den Wesenskern.
Hä???
Ab C99 gibt es bool, true und false, die sich wie echte Booleans verhalten. Also nur die Werte 0 und 1 annehmen können. Was brauchst du noch?
Wie jetzt? Es muss doch heissen "nur die Werte /zwischen/ 0.0 und 1.0". Wie will man sonst die-ganze-Wahrheit von der einfachen Aussage unterscheiden? Hier ist for(;;) auch wieder überlegen, weil, wie lange läuft eine Endlosschleife while(true) mit true = 0.99?
Aus Sicht des Sprachstandards nicht wirklich, beides ist "the implementation". Dass man "true" und "false" so spät nicht einfach ohne Headerfile neu definieren durfte, ist einfach mal den vielen existierenden Programmen geschuldet, die sowas vorher selbst definiert haben durften. Der Typ _Bool ist aber dennoch intrinisch, denn dessen Bezeichner liegt im implementation namespace. <stdbool.h> mappt ihn dann nur auf bool.
Das ist natürlich Quadratunsinn! Im K&R steht es EXPLIZIT drin. K&R Ed.2 page 56
Nicht nur drüber reden … LESEN! Ich schreibe die Endlosschleife immer so:
denn ich finde die Überraschung muß am Ende kommen.
Stark! Toller fehlertoleranter Compiler.
Parabelförmig vomittierend…
Klarer Syntaxfehler von mir. Davor hätte mich bestimmt der Compiler gewarnt. Mir fehlt nur noch eine Begründung wie man das doch noch als Richtig erklären könnte. Dann wäre es Thread Konform. :-) :-) In C++ sollte man ganz klar nur noch HOFs für Iterationen verwenden:
;-)
Genau das meinte ich weiter oben, als ich davon sprach, dass es keine richtige Bedingung sei. Technisch ist es natürlich eine Bedingung, aber ich schreibe sie nur hin, weil sie eben formal nötig ist und nicht, weil ich tatsächlich eine will.
… dann sollte man sich mal schleunigst daran machen, den Code sauberer zu strukturieren.
Wo das im C-Standard steht, wird für die wenigsten relevant sein, weil sie da eh nicht reinschauen. Wichtiger ist, wo es im Lehrbuch steht, und die Optionaliät der drei Ausrücke in einer for-Schleife wird da doch hoffentlich im Kapitel über Schleifen drin stehen, sonst taugt es nicht viel. Und ich finde es im übrigen sehr wohl intuitiv, mehr noch als wenn ich irgendwas als Bedingung hinschreiben muss, nur um der Form genüge zu tun.
Das wäre nun wirklich an den Haaren herbeigezogen. Warum hätten sie die Bedingung dann überhaupt optional gemacht? Eine extra eingebaute zusätzliche Option, nur um explizit Schleifen schreiben zu können, die niemals ausgeführt werden? Das ergäbe nun wirklich gar keinen Sinn.
Hier hat jetzt genau einer mal nachgefragt. Es gibt hier zu allerhand Bestandteilen verschiedener Sprachen Fragen. Das bedeutet nicht, dass das alles völlig unintuitiv ist.
Bis auf das "es" sind wir uns da einig. Für mich ist "es" die Bedingungslosigkeit der Schleife, denn das ist es ja, was ich eigentlich erreichen will. Und Bedingungslosigkeit drückt man am besten dadurch aus, dass man keine Bedingung angibt.
Was lisp kann (Klammernorgien), das bekommen wir in C++ doch auch locker hin. ;-)
Was er vergessen hat zu erwähnen ist, warum er eigentlich immer noch mitliest, wenn er die Diskussion so blöd findet.
Wenn Du explizit das Fehlen von etwas hinschreiben möchtest, dann brauchst Du dafür eben ein Konstrukt, was Du schreiben kannst. Also etwa:
Könnte man natürlich (in C++) machen. Oder in C eben mit for(;"ever";); Wenn Du etwas weglässt, ist es eben nicht mehr explizit, sondern implizit.
Während in Lisp hauptsächlich runde Klammern verwendet werden, kann man in C++ alle Klammersymbole, die ASCII hergibt, also ()[]{}<>, fast nach Belieben mischen. Ich würde übrigens im obigen Lambda-Ausdruck die leere und deswegen optionale Parameterliste explizit hinschreiben, weil sonst – ähnlich wie bei der weggelassenen Bedingung in for(;;) – überhaupt nicht klar ist, was der Compiler dafür einsetzt. Also so:
Wilhelm schafft es sicher auch noch, das Beispiel mit ein paar Template-Klammern (<>) aufzuhübschen, dann sind wir nicht mehr weit weg von der Programmiersprache ], die zu einem würdigen Nachfolger von C++ werden könnte:
Es fehlt doch aber nichts.
Warum sollte ich was hinschreiben müssen, um damit auszudrücken, dass es eigentlich nichts zum hinschreiben gibt? Tschuldigung, bin spät dran den Thread weiter laufen zu lassen. :-) https://pclintplus.com/gmp/demo/
C11/No Standard Library Autosar19: note 9177: condition of 'while' statement has non-Boolean type 'int' [AUTOSAR Rule A5-0-2] info 716: infinite loop via while MISRA C 2012: note 9036: essential type of condition of 'while' statement is 'signed8' but should be boolean [MISRA 2012 Rule 14.4, required] info 716: infinite loop via while Die Info 716 wird immer getriggert, also nach MISRA und Autosar ist while(1) praktisch doppelt böse. :-) BARR-C 2018 hatte ich ja schon erwähnt. Im SEI CERT C Coding Standard habe ich spontan nichts gefunden, also im Netz, die Präferenz scheint da aber bei while(true) zu liegen.
MISRA C 2012: info 716: infinite loop via while supplemental 893: expanded from macro 'true' (line 17) Interessant fände ich jetzt noch andere Beispiel von Coding Guidelines. Ich habe gerade die ISO/IEC 17961 gefunden, bzw. natürlich nur den Hinweis und nicht den Standard selber. https://www.iso.org/standard/61134.html
Ich bin erschüttert. Richtige Betriebssysteme brauchen Endlosschleifen, aber die NASA nicht.
Dieses 100-Seiten Werk erwähnt solche Schleifen mit keiner Silbe. Edit: linux-source-4.19/Documentation/process/coding-style.rst schreibt auch nichts vor.
Das geht in C auch ;-) Allerdings ist in C die Wahrscheinlichkeit, dass sich dadurch ein valides C Programm ergibt, geringer.
Leider falsch. Wenn Du in for(;true;) oder for(;false;) den Boole'schen Wert weglässt, wird dafür (in C) ein implementation-defined Wert != 0 eingesetzt. Wenn Du in dem Lambda-Ausdruck {} die leere Parameterliste weglässt, wird die durch nichts, auch nichts anderes ersetzt. Also so:
Hatte ich doch schon, oder?
Gast
#7478984
Naja es gibt halt neben "richtigen" Betriebssystemen auch Betriebssysteme die im Space steuerbar sein müßen. Da sind Endlosschleifen das letzte was man will, siehe bspw. WatchDogtimer.
Nun, wenn es ein Task ist, welcher die lebenserhaltenden Systeme steuert und überwacht … also ich hätte da schon gerne eine Endlos-Schleife. ;-)
Ich denke auch, dass es eher unschön ist, wenn beim Wiedereintritt die Raketensteuerung aussetzt, weil sich das Programm beendet hat.
Na sicher wird sie das - durch eine leere Parameterliste. Das steht so im C++-Standard: "If a lambda-expression does not include a lambda-declarator, it is as if the lambda-declarator were ()." Also darfst du sie deiner eigenen Logik folgend nie weglassen.
Nix falsch (Rolf hat dich auf deinen Trugschluss bereits hingewiesen). Weil dir keine echten Argumente mehr einfallen, begibst dich gerade auf das Niveau der reinen Wortklauberei. Lass es mich dir noch etwas ausführlicher erklären, als es Rolf bereits getan hat: Natürlich hast du insofern recht, dass bei der Spezifikation des for-Statements im C-Standard das Wort "replaced" auftaucht: "An omitted expression-2 is replaced by a nonzero constant." In der Spezifikation der Lambda-Expression im C++-Standard wird der entsprechende Sachverhalt mit "as if" formuliert: "If a lambda-expression does not include a lambda-declarator, it is as if the lambda-declarator were ()." Da auch beim for-Statement die as-if-Regel gilt, kann der obige Satz ohne die geringste Änderung seiner Aussage wie folgt umformuliert werden: "If a for statement does not include expression-2, it is as if expression-2 is a nonzero constant." Uns siehe da, das "replaced", an dem du dich so festkrallst, ist weg, und die fehlenden expression-2 wird einfach durch nichts ersetzt. Genauso gut kann der Satz mit dem lambda-declarator ohne die geringste Änderung seiner Aussage wie folgt formuliert werden: "An omitted lambda-declarator is replaced by ()." Jetzt steht auch hier ein "replaced". Die fehlende Parameterliste wird also durch die leere Parameterliste (ein einfaches Klammerpaar) ersetzt. Wer also darauf besteht, im Kopf einer Endlosschleife die Bedingung "true" hinzuschreiben, der sollte konsequenterweise bei parameterlosen Lambda-Ausdrücken die leere Parameterliste hinschreiben. Wenn du das partout ablehnst, hat es wenig Sinn, mit dir weiter über Logik in der Programmierung zu diskutieren.
Gast
#7479294
Nun, bei Gemini-7 war gerade die nicht beendbare Lagesteuerung das Problem, das fast zum Exitus der beiden Astronauten geführt hätte. https://youtu.be/vRKnl0FCEgI?t=25 Und der Iwan denkt auch nicht ans aufhören sondern feuert bis der Tank leer ist. Lass doch den Rest der Welt heulen und fordern, dass irgendwer immer die eine Steuermöglichkeit haben muß, wer im Funkschatten sitzt, sitzt am ruhigsten: Und wenn sich ein Unterprogramm unerwartet beendet, kann es immer noch von einem Master(-programm) neugestartet werden. Eine unendliche Schleife bedeudet nun mal kontrolleinschränkung/-verlust für einen Supervisor.
Ich bestehe nicht darauf und habe nicht darauf bestanden: ich habe nur gesagt, dass for(;;) weniger explizit als while(true) ist. Und da Rolf M. nicht weiß, was explizit ist, habe ich geschrieben, dass for(;true;) explizit ist, nur um ihm und Dir das klar zu machen. Ich habe nicht darauf bestanden, ein true hinzuschreiben.
Nein, beides hat gar nichts miteinander zu tun. Es sind konzeptionell unterschiedliche Dinge, die dort passieren. Das eine ist der Ersatz für einen nicht-vorhandenen Ausdruck, und ein Ausdruck liefert einen Wert. Und das andere ist die Möglichkeit, eine leere Parameterliste auszudrücken, also kein Ausdruck und damit kein Wert. Man kann sich nur darüber unterhalten, ob eine leere Parameterliste (leere Menge) oder eine nicht-vorhandene Parameterliste (nicht existierende Menge) gleich ist. Da in beiden Fällen kein Statement des Blocks des L-Ausdrucks etwas der leeren Menge oder der nicht-existierenden Menge referenzieren kann, ist beides aber konzeptionell identisch. Es findet auch kein Ersatz durch irgendeinen Standardwert statt.
Ich habe das nicht abgelehnt, auch nicht überall. Du hast das ins Spiel gebracht.
Die Texte im C++-Standard sind übrigens (falsch von Dir wiedergegeben, Du hast C und C++ Standard vermengt):
und
Hallo, Wilhelm M. schrieb im Beitrag #7479310:
Da fehlt was. rhf
Natürlich sind das zwei verschiedene Dinge, da muss man sich nicht lange darüber unterhalten. Allerdings wird in Lambda-Ausdrücken eine nicht vorhandene Parameterliste gleich behandelt wie eine leere. Ebenso wird eine nicht vorhandene Bedingung in einer for-Anweisung gleich behandelt wie eine immer erfüllte. Ob das optionale Ding ein Ausdruck oder eine Parameterliste ist, macht meiner Meinung nach für Diskussion, die wir hier führen, keinen Unterschied. Für beide gilt: Entweder man schreibt es explizit hin, oder man lässt es weg, dann wird es implizit festgelegt.
Das Thread-Thema ist for(;;) in C:
Deswegen habe ich dafür den C-Standard herangezogen. Die Lambda-Ausdrücke, die du ins Spiel gebracht hast, gibt es aber nur in C++, deswegen habe ich dort den C++-Standard zitiert. Ich hätte natürlich auch für for(;;) den C++-Standard zitieren können. Da sich dort der entsprechende Satz vom C-Standard nur in der Formulierung, nicht aber in seiner Aussage unterscheidet, hätte dies an meiner Argumentation nichts geändert.
Falls du das Semikolon meinst: Das ist bereits im init-statement enthalten.
Natürlich sind sie unterschiedlich. Eine Funktion braucht immer eine Parameterliste. Diese kann leer sein. Im Falle von Lambdas (und nur dort) hat man eben entschieden, dass sie nicht angegeben werden muss und dass das exakt so behandelt wird, als hättest du eine leere Parameterliste angegeben. Genau das sagt doch auch der von mir zitierte Satz aus dem Standard. Übrigens würde ich eigentlich erwarten, dass du nicht nur () schreibst, sondern "explizit" hinschreibst, dass die Parameterliste leer sein soll, also (void). Wenn du das weglässt, ist sie ja nur noch implizit leer, und explizit ist doch immer besser als implizit.
Der Standardwert ist die leere Liste.
Und was, wenn sich mangels Endlosschleife das Master-Programm beendet hat?
Wenn es um Software im Sinne von manuell gestarteten Programmen geht und seine Ausführung die Möglichkeit blockiert, andere Programme zu starten, ja. Auf der anderen Seite stehen µC-Anwendungen, bei denen es essenziell ist, dass das Programm als Endlosschleife läuft, denn wenn es sich beenden sollte, passiert je nach dem entweder irgendein Blödsinn, der Watchdog macht einen Reset des Systems, oder der µC läuft in eine leere Fallback-Endlosschleife. In der Regel will man keins davon. Das gleich gilt letztendlich auch für dein Master-Programm / Betriebssystem.
Gast
#7479380
Liste ist ein Datentyp, aber keine Anweisung/Conbtrol-Struktur. C kennt im Standard keine Liste, höchstens pointer, bitfields und structs als komplexere datentypen.
Du bist genauso ein Wortklauber wie der Wilhelm. Es dürfte doch aus dem Kontext mehr als klar hervorgehen, dass mit "Liste" die Parameterliste gemeint ist.
Doch. In stdbool.h gibt es bool, ist als der Typ _Bool definiert. Man kann _Bool natürlich auch direkt verwenden. Seit C23 sind true, false und bool keywords, das heisst man braucht stdbool.h und auch _Bool nicht mehr. bool hat einige interessante Eigenschaften.
Und ja, auch ein Wert vom typ (_Bool){1} gibt es, also ein echtes true, das sind nicht simple ints:
Ausgabe:
Es ging nicht um Datentypen, sondern um Parameterlisten. Und die sind selbstverständlich im C-Standard definiert: parameter formal parameter formal argument (deprecated) object declared as part of a function declaration or definition that acquires a value on entry to the function, or an identifier from the comma-separated list bounded by the parentheses immediately following the macro name in a function-like macro definition
Gast
#7479389
In Sicherheitskritischen Anwendungen wie Space/Avionic will man aber eine "last resort" Signal-Möglichkeit um das System schnell und mit definierte Latenz in einem "Safe harbour" Zustand zu bringen. Oder eben Reboot. Und natürlich macht nur ein von einem Blödian designtes System "Blödsinn" nach Beendigung einer Schleife. Ein von einem Kompetenten Systemdesigner designtes System geht mach programmabarbeitung in einen definierten Zsutand ("Power-Down, Hibernate, ...). Falls die Mittel der Software dazu nicht ausreichen muß eben die Hardwareabteilung entsprechende Abschaltungen (Tri-State, gemeinsames Potential, inert state) vorsehen. Aber wie schon das wording "System" hinweist, geht eine solche Betrachtung weit über den Horizont eines niedrig-hierarchischen Endlos-C-Schleifen-Programmieres hinaus. Die NASA hat eben ihren guten Gründe auf in irdischen Massstäben übliche Programmierweise zu verzichten respektive als bekannt unsicher zu verbieten.
Gast
#7479390
Also das hinter dem 'for' in Klammern heisst jetzt "Parameterliste" wie bei einem Funktionsaufruf?? Das sind aber nun mal aber im syntax-Sinne keine Parameter sondern Anweisungen. Deshalb finden sie sich auch im Code- und nicht im Data-segment. Jetzt haben die Väter von C explizit eine kurze und konsistente Endlosschleife realisiert und favorisiert ohne andere Konstrukte einzuschränken ... und hier wird ernsthaft argumentiert, das nicht zu nutzen. Ein Anfänger weiß nicht, dass i++ äquivalent ist zu i=i+1. Der Code wird aber nicht besser, wenn man auf ++ verzichtet.
Ich sehe diese Diskussion auch als nutzlos an. Man kann in C eine Endlosschleife auf verschiedene Art und Weise produzieren... na und? Wenn verschiedene Arten angeboten werden, dann kann man die auch nutzen. Ob die eine oder andere "besser" ist, spielt überhaupt keine Rolle. Der Compiler erzeugt da ganz emotionslos denselben Code. Deshalb verstehe ich diesen ganzen Hickhack um Begriffe hier auch nicht. Der eine oder andere hier mag sich bitte mal besinnen und sich fragen, ob diese kleinkarierte Diskussion überhaupt der Mühe wert ist.
Gast
#7479415
Weder konsistent noch favourisiert und "kurz" ist bezüglich der Forderung nach verständlichen Code auch mehr von Nach- als Vorteil. Werdet doch endlich mal erwachsen und insestiert nicht, wie es damals die "Väter" in Ihre Tontafel ritzten, sondern wie es Euch und Eurer Zeit nutzt. Man läuft doch auch nicht mehr in den gleichen Klamotten wie die Väter damals ... Echt, manche haben hier im Forum weniger Selbstbewusstsein, Pragmatismus und Autonomiestreben als die Aimish oder ein Haufen Schläfenbelockter Talmud-Schüler. SCNR https://youtu.be/pc04f4w17rM?t=290 https://de.wikipedia.org/wiki/Pragmatismus Aber eigentlich muss man ja nicht sofort zu einem einstimmigen Fazit kommen, manchmal genügt es festzustellen, das manche reifer sind als andere aber noch nicht alles Wasser den Nil abwärts geflossen ist ...
Eben, goto ist hier das beste Angebot um eine eine unbedingte Schleife zu schliessen. Aber Goto ist ja böse - hat 'Papa' gesagt.
Auch wenn ich Dir in diesem Thread fast nirgends zustimme, so ist das genau das, was ich hier Beitrag "Re: for(;;){} Schleife" schonmal als "katholisch" bezeichnet hatte. Demnächst wird noch gefordert, dass man doch besser zu den "halben" Funktionsprototypen im K&R-Stil zurückkehren sollte. Bemerkenswert, wie man sich derart ernst und so lange mit einem derart lächerlichen Thema befassen kann.
Beitrag #7479423 wurde von einem Moderator gelöscht.
Gast
#7479424
Naja statt "Katholisch" sollte man besser "dogmatisch" schreiben. Weil auch unter den 74% Nichthatholen in .de gibt es ziemlich viele die zu bequem zum selber nachdenken sind. https://upload.wikimedia.org/wikipedia/commons/2/2e/Konfessionen_Deutschland_Zensus_2011.png https://de.wikipedia.org/wiki/Dogma
Dein Problem, nicht meins.
Ich fordere die komplette Abkehr von dieser kaputten Sprache. Das war noch vor meiner Zeit. Es gibt aber durchaus Situationen, in denen ich die alte Schreibweise noch hätte gebrauchen können, wenn es sie noch gäbe.
Das kannst du sehr professionell bewerkstelligen: Stecke einfach den Kopf in den Sand. Es gibt ja auch ›gute‹ Programmiersprachen für den Vogel Strauß, ›Scratch‹ fiele mir da ein, oder ›Turtle-Graphics‹
Nein, wie kommst du denn darauf?
In C gibt es kein Code- oder Data-Segment. Abgesehen davon hat das auch rein gar nichts mit Parameterlisten zu tun.
Ich habe das nicht nach den "Vätern" gemacht. Ich wusste nicht einmal, dass das im K&R so steht, bevor es hier jemand zitiert hat. Ich habe selbst für mich entschieden, dass ich diese Form für Endlosschleifen bevorzuge, und zwar primär, weil ich die eigentlich unnütze Bedingung nicht angeben muss. Das macht es für mich einfach zur natürlicheren Wahl für eine unbedingte Schleife. Ich war dann aber doch sehr erstaunt, als Wilhelm das als "an den Haaren herbeigezogen" betitelt hat.
Für Endlosschleifen ist es auch nicht wirklich sinnvoll. Es gibt aber sinnvolle Anwendungsfälle von goto, und dort verwende ich es dann auch.
Gast
#7479468
Doch hat es, Parameter sind Daten und Zuweisungen sind Instruktionen.
Neee wie Du das für Dich entscheidest interessiert kein Schwein und kein Compiler. Du hast hier garnichts "selbst" zu entscheiden, du hast (wie jeder andere auch) korrekten und möglichst verständlichen Syntax zu schreiben. Und für viele ist eben eine Ausage wie etwas nicht ist (Eine unendliche Schleife ist wie eine Schleife ohne Parametreliste) nicht sonderlich erklärend. Im Hitchhiker und anderer Belletristik finden sich solche Gedankenmuster, die etwas über ihre Nicht-Sein erklären wollen, bspw.: "Fliegen heißt Lernen sich auf den Boden zu schmeißen und ihn zu verfehlen. Flying is learning how to throw yourself at the ground and miss."
Doch gerade bei Endloschleifen ist das sinnvoll. Weil ja der Sinn (und das Compilat) hinter einer "Endlosschleife" der unbedingte Sprung ist. Und welches Schlüsselwort hat C für "unbedingten Sprung" vorgesehen? Eben, "Goto" .
Parameter landen aber in der Regel in Registern oder auf dem Stack, und das true in der Schleifenbedingung ist keine Zuweisung, sondern ein Ausdruck, der vom Compiler üblicherweise komplett wegoptimiert wird, also nachher meist gar nirgends landet. Das ist aber alles wie gesagt in C nicht spezifiziert, sondern komplett vom Compiler abhängig und damit in diesem Zusammenhang irrelevant.
Dass es dem Compiler egal ist, haben wir vor langem bereits festgestellt. Und ob es ein "Schwein" interessiert ist mir egal, denn für die schreibe ich den Code nicht. Ich schreibe ihn abgesehen vom Compiler für Programmierer, die der Sprache zumindest auf einem gewissen Grundniveau mächtig sind. Wer nicht mal weiß, wie eine for-Schleife funktioniert, soll lieber die Finger davon lassen, bis er es gelernt hat.
Ich kann sehr wohl entscheiden, wie ich meinen Code schreibe, denn du bist nicht die Codepolizei, die mir das verbieten könnte. Und ja, ich habe mich dazu entschieden ihn korrekt und möglichst verständlich zu schreiben. for (;;) ist weder inkorrekt, noch unverständlich.
Das ist wie bei den meisten Stilfragen und wie auch hier schon öfter angemerkt wurde, etwas subjektives. Ich finde es klar, lesbar und einleuchtend. Das magst du anders sehen, aber das ist dann eben deine persönliche Sichtweise, sprich: Du hast für dich entschieden, dass du eine andere Schreibweise bevorzugst - oder jemand anders hat das für dich entschieden, und du folgst dem nur dogmatisch. Mehr Optionen gibt's da nicht.
Mit der Argumentation kannst du alle Schleifen per goto umsetzen, denn mit einem if kannst du dem ja auch eine Bedingung hinzufügen. Aber eine Schleife wird in C nunmal üblicherweise mit for oder (do/)while und einem Codeblock geschrieben. Warum sollte ich davon bei einer Endlosschleife abweichen? Das wäre tatsächlich unintuitiv. Ich würde aus Gründen der Lesbarkeit generell davon abraten, goto für Rückwärtssprünge zu verwenden.
Wie so oft in diesem Forum wurde auch in diesem Thread die Frage des TE schon nach kurzer Zeit korrekt beantwortet, worauf sich eine Diskussion über angrenzende Themen anschloss, die für einige interessant sein mögen, für andere nicht. Wer den Thread nur deswegen öffnet, weil er dasselbe Problem wie der TE hat und ausschließlich an der Antwort auf die Ursprungsfrage interessiert ist, kann den Thread schon nach wenigen Minuten wieder verlassen. Wer an einer weiterführenden Diskussion interessiert ist, bleibt drin. So kommt letztendlich jeder auf seine Kosten. In diesem Forum herrscht diesbezüglich eine andere Kultur als bspw. auf stackoverflow.com, mikrocontroller.net hat aber IMHO auch weder das Ziel noch die Ressourcen, ein deutschsprachiges stackoverflow.com zu werden. Dass solche freien Diskussionen auf mikrocontroller.net oft ergebnislos verlaufen, sollte jedem klar sein, der daran teilnimmt. Ob eine Diskussion trotz absehbarer Ergebnislosigkeit wenigstens einen Erkenntnisgewinn liefern kann, muss jeder für sich selbst entscheiden. Ich persönlich finde die Diskussion hier trotz ihrer Bedeutungslosigkeit für die Praxis eigentlich recht interessant. Auf der anderen Seite gibt es hier Threads mit über hundert Teilnehmern und mehreren Tausend Beiträgen, die für mich völlig irrelevant sind, deren Teilnehmerzahl aber auf ein großes Interesse bei anderen Leuten schließen lässt. Auch diese Threads sind für mich völlig in Ordnung, ich schaue dann eben nur selten oder überhaupt hinein.
Es ist unverständlich. "Für nichts" ist kein intuitiver Begriff für eine Endlosschleife.
Und "Während eins" ist besser?
Nicht viel. Deshalb schreibt man ja auch "Während wahr". Bzw "Solange wahr".
Gast
#7479549
Um aber eine Endlosschleife zu realisieren braucht man keinerlei Kenntnisse bzgl des for-Konstruktes. Das zu (;;) verstümmelte for-konstrukt funktioniert nur, weil extra noch ein paar Sonder-Regel eingeführt worden, um den Parser/Compiler das "Kotzen" bei diese unlogischen Notation auszutreiben.
Träum weiter, träum tief - bin ich hier im falschen Film? Da fragt ein TO weil ihm das Konstrukt unbekannt und unverständlich ist. Und dann kommt so ein selbstgefälliges Irgendwas daher und behauptet ungeniert "Das ist ist nicht unverständlich, das ist verständlich." Dann kann man nur noch "Kognitive Dissonanz" diagnostizieren: https://www.bfi-ooe.at/de/blog/warum-wir-uns-selbst-austricksen-ohne-es-zu-merken-kognitive-dissonanz.html "Verschlimmbesserung" ist auch eine Kulturtechnik, um sich nicht selbst die Sinnlosigkeit seiner Existenz eingestehen zu müßen.
Nein, das ist keine Frage des sprachlichen Stils, sondern die nach der Konstruktion eines mathematischen Formelapperates zur Realisation von Algorithmenmaschinen. Eben wie die Turing-maschine. Das "Weglassen" gibt es im Mathematischen Sinne nicht, da gibt es nur ein neutrales Element um eben eine bijektive Abbildung zwischen symbol und Instruktion-Code zu ermöglichen. Ja, ich weiß, die mathematischen Grundlagen interessieren einen 0815 Codierschwein wenig. https://www.cs.virginia.edu/~robins/Turing_Paper_1936.pdf
Das ist aber keine Argumentation bezüglich aller Schleifen sondern nur um den Spezialfall einer degenerierten, da alle wesentlichen Schleifeneigenschaften (Anfangsbedingung, Iterationsanweisung, Anfangsbedingung) fehlen respektive nicht gebraucht werden. Eine " for index in anfangswert bis Endwert-schleife ist also völlig "überdimensioniert". Es ist halt so, also ob man zum Brötchenholen um die Ecke extra den VW-Bully aus der Garage holt statt den kurzen Gang direkt zu erledigen. Am Anfang lernt man for Schleifen meistens so:
Man lernt dann, ok, Initialisierung, Bedingung, und was für nach dem Durchlauf. Dass man das erste und letzte leer lassen kann, ist nicht so erstaunlich. Es gibt ja auch leere Statements (einfach nur ";"), und Parameterlisten von Funktionen kann man auch leer lassen. Aber an einem Ort, wo man den Wert eines Ausdrucks braucht, den weglassen zu können, wie kommt man dort darauf, das man das kann? Egal ob in Zuweisungen, Initialisierungen, Operanden, if Bedingungen, while schleifen, Funktionsaufrufen, etc, dort kann man das sonst nie machen. Die ersten paar Jahre wusste ich nicht, dass man die Bedingungen weglassen kann. Es ist nicht logisch. Es ist überraschend, unerwartet, ein Spezialfall, den man einfach kennen muss! Darum ist meine lieblingsendlosschleife immer noch "while(true)"
So zu argumentieren, bringt nichts, denn
Sagst du das auch im normalen Sprachgebrauch so? Auf was bezieht sich dieses "wahr" bzw. was genau muss wahr sein, damit die Schleife weiterläuft? Endlos ja, aber beachte : !Flags.MotorRunning jetzt schütte ich mal mehr Öl ins Feuer um etwas Perspektive zu präsentieren;-) Früher(TM) genügte es bei kommerziellen Programmier Werkzeugen die zugehörigen mitgelieferten Handbücher zu studieren und erfuhr genug Information um damit in C arbeiten zu können. (KEIL z.B.) Es war in den meisten Fällen NICHT notwendig andauernd die Compiler Standards und andere "highvoluting" akademischen Unterlagen zu recherchieren. Die damaligen Compiler waren auch viel einfacher wie C++ und Abkömmliche. Ohne grosse Theorie und langjähriges UNI-Studium konnte also der "Gelegenheitsprogrammierer" seine Projekte mit den (gedruckten) Unterlagen durchziehen, weil genug Information vorhanden waren. Und ja, Internet war damals für die meisten noch nicht zugänglich. Kostenpflichtige offizielle Dokumente waren ohnehin für die meisten nicht erschwinglich. Wenn also damals dann die Compiler Doku konstatierte, dass eine parameterloses for(;;) wie beschrieben funktionieren soll, dann dachte man nicht mehr weiter daran und hielt sich an die Documentation um funktionierende Programme schreiben zu können. So einfach war das damals und man war effektiv im Job um sein Problem zeitgemaess lösen zu können. Viele damals waren keine Computer Science Akademiker für die "Programmieren" eben hin und wieder nur notwendig war, um ein Problem lösen zu können und keine hochgradige Wissenschaft die nur sich selber zum Ziel hatte. Viele mußten sich die Computer Programmiersprachen selbst beibringen. Die Werkzeuge waren da um deren anfallende Probleme lösen zu können. Im Vergleich zu C sind die esoterischen Funktionen von C++ ohne ausführliches Studium der Compiler Referenzliteratur unleserlich bzw. unverständlich für den nicht-Praktiker. Ein typisches C Programm dagegen, war zumindest nach Lesen von K&R und Werkzeug Dokumention, wenn gut geschrieben, meistens vollkommen verständlich. Das sollte man heute zum Vergleich nicht vergessen. Die heutige Welt mit ihren modernen Sprachen-Produkten wie Java, PHP, Python, Rust, etz. spielt in einer total anderen Liga. Die heutigen Programme zeigen heutzutage aber oft ein hochgradiges Mass an Sprachen Esoterik und Abstraktion, das ohne weiteres Studium nicht mehr ohne Weiteres verständlich ist. Ob das wirklich notwendig ist, kann ich nicht beurteilen. Aus der Sicht eines Akademikers ist das obige natuerlich alles Blasphemie. Aber man sollte berücksichtigen, dass viele Menschen sich damit nur so weit befassen wollen, weil sie ein Problem zu lösen haben. Ist nur meine Meinung.
Welche Relevanz hat das für eine Programmiersprache?
Auf nichts. Steht doch da. Sonst hieße es "Solange X wahr".
Wahr muss wahr sein.
Einer der Hauptgründe dafür, dass so viel Software so ein Sondermüll ist.
Gast
#7479603
Da gibt es mit Folge 13 aus Season 2 von "BigBangTheory" auch ein Beispiel aus der Populärkultur zum korrekten Umgang/Notation mit/von Endlosschleifen. https://youtu.be/7dz-7T9HYic?t=45 Bei Sheldons Freundschaftsalgorithmus scheint eine Endlosschleife jegliche soziale Anstrengung ad absurdum zu führen, bis "der Ingenieur im Team" das Verfahren mit einem Schleifenzähler, Abbruchbedingung zur LOA ( am wenigsten unangenehm - "Least Objectionable Activity") entschärft bzw. zu einem Abschluss bringt. Im Anhang Programmablaufplan mit endlosschleife und debuggt Man sieht, ohne Abbruchbedingung funktioniert die Show nicht. SCNR ;-) https://www.myfanbase.de/the-big-bang-theory/episodenguide/?eid=4367
Das ist eine sehr unglückliche Formulierung. Besser: Die Option, eine Bedingung wegzulassen ist genau dafür eingeführt worden, um damit Schleifen formulieren zu können, für die man keine Bedingung möchte.
Und wenn morgen einer fragt, was denn das komische * nach dem Typ ist, dann benutzt du nie mehr Pointer, weil die unverständlich sind? So ein Forum ist nunmal auch dafür gedacht, dass Leute Fragen stellen, weil sie noch nicht alle Grundlagen kennen. Aus einer einzelnen Frage lässt sich nicht schließen, dass etwas unverständlich ist. Hab ich aber oben eigentlich schon mal erwähnt. Ich bin mir auch ziemlich sicher, dass er es nach der ersten Antwort gleich verstanden hat und jetzt für den Rest seines Lebens weiß. [Beleidigungen entfernt…]
Na sicher. Die Sprache bietet verschiedene syntaktisch korrekte Möglichkeiten, eine Endlosschleife zu formulieren. Semantisch können sie als äquivalent angesehen werden, weil das Verhalten des Programms in allen Varianten das gleiche sein wird. Welche davon man verwendet, ist also selbstverständlich eine Frage des sprachlichen Stils und nichts anderes.
Die grundlegende Eigenschaft einer Schleife ist die Wiederholung. Der Rest sind optionale Zusätze, die man manchmal, aber nicht immer braucht.
Genau deswegen kann man die drei in diesem Fall überflüssigen Ausdrücke ja weglassen, statt sowas wie for(true; true; true) oder derlei hinschreiben zu müssen.
Und du findest es umgangssprachlich ganz normal, wenn man sagt, dass man etwas so lange tut, wie wahr wahr ist?
Gast
#7479624
Nein, da stehen keinen Beleidigungen und da wurde auch nichts entfernt... Das mit der kognitiven Dissonanz, also "Tatsache A" sehen und "Story B" erzählen oder die im Link beschriebene Verhaltensweise "Warum wir uns selbst austricksen ohne es zu merken" zeigst Du ziemlich oft im thread. ;-) SCNR
Keine. Aber warum schreibst du dann:
Für mich ist "solange wahr" genauso intuitiv oder unintuitiv wie "für nichts", weil beides kein korrektes Deutsch ist.
Hmm, seltsam. Ich dachte immer, dass sich ein Adjektiv auf ein Substantiv beziehen muss.
Ach so. Wie sieht es dann aus mit while(false)? Nach deiner Argumentation muss dann falsch falsch sein, damit die Schleife weiterläuft. Ich würde mal behaupten, dass falsch immer falsch ist, also könnte nach deiner Argumentation eine Endlosschleife auch mit while(false) eingeleitet werden. Was lernen wir daraus? Man sollte sich bei der Programmierung nie auf die Intuition verlassen. Für eine Programmiersprache gibt es (im Gegensatz zu natürlichen Sprachen) eine umfassende Spezifikation sowohl der Syntax als auch der Semantik, da ist Intuition weder notwendig noch zielführend. Ich kann deswegen nur wiederholen, was hier schon oft geschrieben wurde: Wenn ihr ordentlich programmieren wollt, dann besorgt euch ein Buch zur betreffenden Programmiersprache und arbeitet es von der ersten bis zur letzten Seite durch. Dann bedarf es keiner fraglichen Hilfsmittel wie Intuition oder die Übersetzung von Programmkonstrukten in natürliche Sprache. Wenn ihr dann Code von anderen vorgesetzt bekommt, ist es völlig unerheblich, ob dort Endlosschleifen mit for(;;), while(1), while(true) oder goto formuliert sind, weil ihr alle 4 Varianten versteht.
Wo habe ich das gesagt?
Dann kann man die Endlosschleife ja auch quibbelbobbel nennen. Das ist nach deiner Logik dann ja genau so gut wie for(;;)
bricht sofort ab, weil false ganz offensichtlich false ist und nie true werden kann.
Hä? Nein. Unsinn.
Warum sind die C-Schlüsselwörter dann in Englisch, wenn das doch schlecht ist und man stattdessen lieber alles aus einem Buch von Grund auf lernen soll? Man könnte 'if' ja falschverstehen. Lieber 'quappelsack' verwenden.
Gast
#7479680
Naja, aber verpflichtende Code-Stile wurden doch gerade eingeführt, weil eben nicht davon auszugehen ist, das jeder im Team jede syntaktische Sonderlocke beherrscht. Hinzukommt bei Sicherheitsrelevanter Soft wie für Avionik oder Medizintechnik, das man die Compiler in ihrer benutzten Version zertifizieren muß, also sicherstellen, das bei den benutzten Syntax-Gekröse immer das selbe raus kommt. Damit diese Testerei nicht ausartet, schränkt man eben die benutzten varianten ein. Also eben Projektweit eine Variante eine Schleife zu implementieren und nicht alle 88 Möglichen. Gern wird auch die Richtung und eine Grenze der Iteration vorgegeben, bspw. Down to 0. Das macht auch dem Tester das Leben beim Schreiben der corner cases einfacher. Also eben KISS Prinzip, auch bei der AusWahl der synonymen Source-Code-Optionen. https://en.wikipedia.org/wiki/Programming_style PS: Natürlich kann man sich auch vom nerdigen Spass beim Progrrammieren leiten lassen. Das führte wohl zu der Vermutung, das Dennis Ritchie und Brian Kernighan "C" als Scherz ("Hoax")/Persiflage zu Pascal andachten und nie als ernsthaftes Programmiersprache sahen. Sie sollen sich auch angeblich entschuldigt haben. ;-) https://www.cs.cmu.edu/~jbruce/humor/unix_hoax.html Zitat: "We stopped when we got a clean compile on the following syntax:
At one time, we joked about selling this to the Soviets to set their computer science progress back 20 or more years. "
Es ist aber andrerseits durchaus vorstellbar, daß auch Computer Science Nichtakademiker klare und logisch fundierte Praxis Programme erdenken können die im Kontext ihrer Tätigkeiten täglich benötigt werden und die Doku der eingesetzten Sprache verstanden worden ist. Auch ist es vorstellbar, daß unzählige Elektronik Ingenieure in der Vergangenheit und Gegenwart funktionell erstklassige Produkte mit den in der Uni absolvierten Kursen programmieren können. In Fakt, es ist sogar vorstellbar, daß viele embedded Produkte der Vergangenheit deswegen einwandfrei und zügiger funktionierten und keine Cloudanbindung zu häufigen SW Upgrades benötigten. Böswillige Zungen behaupten auch heute noch, daß embedded Geräte der Vergangenheit oft sogar besser funktionierten als viele der überzüchteten Sachen der Gegenwart die ohne Anbindung ans Mutterschiff und deren fragilen Wolkenbänken nicht mehr richtig oder überhaupt funktionieren und ewig zum Neu-Booten brauchen. Leider sterben die Leute aus, die es besser erlebt haben und man kann nicht mehr vergleichen, weil die User der Gegenwart es nicht besser erlebt haben. Ein VCR oder CD-Abspielgerät funktionierte praktisch sofort, während sich das DVD Abspielgerät minutenlang plagt um überhaupt verwendungsfähig zu werden. Vielleicht gibt es dazu gute Gründe, wer weiß, nur versäumen es die Hersteller es zu erklären warum so vieles Zeugs lahme Enten sind. Aber was weiß ich, Fossil der Vergangenheit. der vergleichen kann?
Es ergibt sich aus dem von dir geschriebenen. Du meintest, "solange wahr" sei intuitiv, und auf die Frage, was denn überhaupt wahr sein müsse, weil der Satz unvollständig ist, meintest du:
Nur wenn man meint, es müsse unbedingt 1:1 auf gesprochene Sprache abbildbar sein. Das scheinst aber nur du so zu sehen. Aber das passt ja auch schon für klassische Zählschleifen nicht:
Wenn man die einfach 1:1 in gesprochene Sprache übersetzt, kommt in etwa sowas raus: "Für erzeuge neuen integer i und initialisiere ihn mit Wert 0, ist i kleiner als 10? und inkrementiere i." Das ergibt sprachlich auch nicht viel mehr Sinn. Deiner Argumentation nach müsste man dann also for-Schleifen generell komplett umbauen, weil sie sonst nicht intuitiv sind.
Ja? Software war früher besser? Ich muss dich enttäuschen. Das ist die typische früher-war-alles-besser Verzerrung. Software war früher noch viel beschissener als heute. Aber das heißt nicht, dass Software heute gut ist. Glaubst du nicht? Dann installiere doch nochmal MS-DOS auf einem alten Rechner. Oder Windows 95. Oder spiele nochmal ein Spiel auf einem C64. Das ist aus heutiger Sicht gesehen sowohl von der UX als auch von der Softwarequalität absoluter nuklearer Kernschrott. Die "gute alte Zeit" gibt es bei Software nicht. Auch nicht im Embedded-Bereich. Schonmal ein Golf-3-Steuergerät ausgelesen? Oder jedes beliebige andere Gerät mit Firmware drauf aus den 90ern. Absoluter Schrott war das aus heutiger Sicht.
Aha. Danke für die Bestätigung, dass ich das gar nicht gesagt habe.
Nur, wenn man mit dem Klammerbeutel gepudert wurde. Normale Menschen lesen das als 'for i from 0 to one less than 10'.
Das ist in der Tat wahr. Die C-for-Schleife ist einfach nur veralteter Schrott. Heute macht man das mit Iteratoren viel intuitiver, lesbarer und sicherer. Die Schrottsprache C beherrscht das aber natürlich nicht.
Nein, meine Argumentation beschränkte sich auf while(true) und for(;;).
Möglicherweise habe ich deine Aussage
falsch interpretiert. Macht aber nichts, weil das Problem mit der Logik schon vorher begann weder von dir noch von mir aufgelöst werden konnte:
Damit man sie sich besser merken kann, nachdem man einmal ihre Definition gelsen hat. So etwas nennt man auch Gedächtnisstütze (engl. Mnemonic) und hat mit Intuition wenig bis gar nichts zu tun.
Achso.
Man muss nur lernen, dass 'bang' eine Bedingungsabfrage ist und 'shoot' der Funktionsabbruch. Intuition ist ja was böses, deshalb sind diese Keywords besser als 'if' und 'return'. Die könnte ja jemand falsch verstehen.
Dann hast du dich wohl nur ungeschickt ausgedrückt, denn so kam es rüber.
Ach komm, jetzt machst du dich lächerlich. Erst sprichst du von "für nichts" und sagst, das sei doch so unintuitiv, weil du es wörtlich nimmst, und jetzt sagst du bei einem anderen Beispiel, dass man das doch nur anders lesen muss. Und bei diesem gebe ich dir auch recht.
Die einzige Sprache, die ich kenne, die Zählschleifen mit Iteratoren macht, ist Python. Damit könnte man sicherlich auch Endlosschleifen machen, aber das wäre dann doch eher ungewöhnlich.
Wie nimmt man 'nichts' denn unwörtlich? Wenn man 'nichts' als 'ever' interpretieren kann, dann auch als 'never'. Eine Zählschleife, bei der Werte angegeben sind (also mehr als nichts), kann man hingegen nicht ohne diese Werte interpretieren. Nichts kann man als alles interpretieren. Das ist der Unterschied.
Ganz im Gegenteil. Endlose Generatoren sind ziemlich üblich. Auch in Python.
Wenigstens hast du eine lustige Phantasie :)
Jede Fachsprache tut gut daran, der Intuition möglichst zu entsprechen. while tut das, for oder ++ weniger. Und for(;;) noch weniger. Es wiederspricht aber auch nicht wirklich, so dass man es übernehmen kann mit den Jahren. Ein Anfänger muss dann halt einmal nachschlagen. So wie jede Operator-Prioritat auch, wenn er kein Lisp-Programm daraus machen will ;-)
Dummerweise sind die Menschen verschieden, einschliesslich dessen, was sie als intuitiv empfinden. Obendrein verändert sich die Intuition mit der Beschäftigung mit allerlei Themen, auch sprachfremden. Wenn du also etwas als nicht intuitiv empfindest, dann kann es sein, dass der Schöpfer der Sprache es sehr wohl so sah. Etwas als intuitiv zu empfinden, verleitet auch dazu, das Lehrbuch zu früh wegzulegen :)
Ja, das wäre äußerst schlimm, wenn Dinge intuitiv funktionieren würden und man sich nicht durch furztrockene Bücher quälen müsste. Schließlich wurde uns früher ja auch nichts geschenkt! Lehrjahre sind keine Herrenjahre!
Mmh, ich bin mir nicht sicher, ob Du mich persönlich meinst. Ich finde dass die Leute bei C einen guten Job gemacht haben. Mit minimalistischen Operatoren und Zucker. Bei Pascal z.B. nehmen häufige Elemente (procedure, begin, end) einen großen Raum ein. In Mathematik nicht. Oder in geschriebener Sprache, wo das kleinste denkbare Zeichen (der Punkt) die wichtigste Bedeutung hat.
Nein, das war allgemein.
Die Deklarationssyntax empfinde ich als Versuch, etwas intuitiv verständlich zu machen, das völlig ins Gegenteil lief. Die ist meinen Augen durch ihre Mischung aus Präfix- und Infix-Operatoren zur Typentwicklung effektiv kontraintuitiv (pointer to array vs array of pointers). Obendrein ist sie auch noch syntaktisch schlecht aufgehängt, wie sich bereits bei den bald nachgereichten typedefs zeigte. Aber da geht's in die Grammatik der Sprache, in Parser und Lexer. nicht ins Visuelle.
Gast
#7479950
Minimalismus ist scheiße, verwendet comments und macht Euch Freunde.
Für solche Aussagen sind manche in die Psychatrie geschickt worden ;-). Stenographie ist auch am Ende: https://de.wikipedia.org/wiki/Deutsche_Einheitskurzschrift#/media/Datei:Stenogr_Notiz_(Lothar_Spurzem)_2009-06B.jpg
Man kann es an der Stelle als "Keine Bedingung" = "unbedingte Schleifenausführung" nehmen. Das würde dann genau dem entsprechen, was C draus macht und auch dem einzig sinnvollen, was man da draus machen kann.
Ganz wie im realen Leben. Mathe ist scheiße und isoliert, Laberfächer sind angesagt, machen Freunde. Für jemanden, der mit APL anfing, liegt C jedenfalls nur kurz vor COBOL. ;-)
Natürliche Sprache wird zum Glück nicht an Universitäten entwickelt (im Gegensatz zu manchen Programmiersprachen). Kein des Lesens kundiger würde "Satzbegin" "Satzende" wollen, wenn er die Elegeanz von Majuskel und Punkt kennt. Bei Pascal hat der Herr Wirth sich was akademisches für Anfänger überlegt.
Das schon. Aber der Herr hatte Sinn für Grammatik. Herr Ritchie nicht. Moin, Was ihr alle gegen C habt:-) Ich finde es eigentlich wegen seiner Einfachheit sogar superelegant. Ursprünglich sollte C bekanntlich ja nur ein Zwischending zwischen ASM und den damaligen existierenden Hochsprachen sein. Ritchie wollte es ja hauptsächlich für Betriebssystem Einsatz vorsehen und repräsentierte eine massive Erleichterung relativ zu ASM. Was mich angeht, liebe ich C einfach deswegen, weil es klare Formulierungen hat und leicht zu merken ist. Die Fußangeln der Sprache muß man natürlich kennen. Aber man kann durchaus mit C effektiv sein. Ist halt Geschmackssache. Seit froh, daß es so viele Alternativen gibt, um mit jener Sprache glücklich zu werden, die einem zusagt. Wenn nicht gerade die Firma vorschreibt welche Sprache in Frage kommt, ist das eine reine persönliche Entscheidung. C++ und neue verbesserte Ansätze, wie vielleicht Rust, sind ja alle recht gut und schön und vermeiden bekannte Schwächen von C/C++, aber wirklich notwendig sind sie für einen großen Bereich von uC Anwendungen auch nicht unbedingt notgedrungen. Es ist noch nicht lange her, daß kommerzielle und freie Hersteller Werkzeuge nur C konnten. Auch da ging es (manchmal fluchend und murmelnd). Nicht jeder muß in kritischen Bereichen arbeiten. Da ist dann gleichgültig was und wie verwendet wird. C++ und ähnliche neue Sprachstandards sind wegen der extremen Flexibilität und Esoterik nur dann einsetzbar, wenn man fortwährend damit arbeitet, um alle Eigenschaften der Sprache dauerhaft im Gedächtnis zu behalten und benötigen oft Recherche um Unklarheiten zu klären. Wer nur gelegentlich programmiert und vielleicht schon betagt ist, wird vielleicht mit (vertrauten) C am Ende doch besser fahren. Nicht jeder ist ein jugendliches Genie mit perfektem Gedächtnis. Im uC Bereich lässt sich fast alles praktisch gut genug in einfacherem C erledigen. Ist C brauchbar? Unbedingt. Gibt es Verbesserungen? Klar. Soll halt jeder wählen, was ihm zusagt. Gerhard
Es wird heutzutage eben sehr gerne gemeckert. Dabei wird gerne mal vergessen: C ist vor 'nem halben Jahrhundert entwickelt worden, für Maschinen die es vor 'nem halben Jahrhundert gab. Und heute wird von einer gewissen Gruppe eben gemeckert. Knapp die eine Hälfte meckert wenn es Anpassungen gibt, knapp die andere Hälfte meckert wenn es keine Anpassungen gibt. Der Rest hat gelesen, gelernt, ist auch mal gestolpert, hat weiter geübt und schließlich ›C‹ für das was es kann Lieben gelernt.
Darf ich es gut kennen, viel genutzt haben, bis hin tief in Compilerbau. und trotzdem Aspekte davon kritisieren? Es gibt mehr als nur Schwarz und Weiss.
Stehst du auf sowas? Ist ja Ok. Aber Knebel und Peitsche sind nichts für mich.
Und genau das meine ich mit ›Meckern‹. Wenn jemand noch nicht einmal ansatzweise diese Programmiersprache zu erfassen vermag, dann flugs ab zu ›Scratch‹ oder ›Turtle-Graphics‹ Habe übrigens gerade noch einmal nachgesehen, es besteht in der Tat keinerlei Zwang ›C‹ zu nutzen. Wie so oft sollte man auf den guten alten Wittgenstein hören: »Wovon man nicht sprechen kann, darüber muss man schweigen.«
Du hast wohl noch nie in einem kommerziellen Projekt mitgearbeitet, oder?
Die Wahrheit tut halt manchmal weh.
Selbstverständlich nicht, ich werkel' seit vierzig Jahren einfach nur so für mich zum Vergnügen im stillen Kämmerlein. ;-) Moin, Warum kann man nicht: "Jedem Tierchen, sein Pläsierchen" gönnen? Gut. C ist über 50 Jahr und man kennt seine Stärken und Schwächen. Ihre Existenz verdankt man bekanntlich der Tatsache, daß man überdrüssig dem ASM wurde und eine hardwarenahe Verbesserung suchte. Das Ziel war nie, eine Hochsprache zu werden. Für solche Zwecke ist C für uC und andere Hardware nahe Aufgaben immer noch gut geeignet. C++ ist aber auch als Hochsprache bewertet, wenn es auch mit Einschränkungen als Mittelsprache geeignet ist. Irgendwie drängt sich deswegen der hinkende Vergleich zwischen Äpfel und Birnen auf. Warum vergleicht ihr andauernd C mit C++ und alles andere darüber? Das finde ich falsch. Im geschichtlichen Kontext findet C durchaus seinen vorgesehenen Platz. Meine Sicht als Target Anwendung für C ist hauptsächlich embedded. Da fällt C durchaus nicht aus seinem Rahmen und hat immer noch eine ausreichende Existenzberechtigung und resultiert in effizienten Binärcode. Als Kapitän eines Schiffes hat er die primäre Verantwortung. Das Gleiche gilt für die Design Entscheidungen des Entwicklers. Da er die Verantwortung trägt, weiß er dann besser was er tut. Er muß entscheiden, wo C++ besser geeignet ist wie C. Auch wenn ihr Experten mit euren Argumenten in manchen Aspekten recht habt, heisst das noch lange nicht, daß andere Lösungsansätze und Werkzeugwahl notwendigerweise falsch sein müssen, nur weil ein neues farbig angestrichenes Pferd, welches sich erst bewähren muß, im Stall steht. Auch ein alter Klepper kann sein Last ausdauernd ziehen. Warum streiten wir uns überhaupt? Was soll die ganze Besserwisserei? Daß die neuesten Produkte der heutigen Zeit angepasst wurden, ist ja verständlich und in modernen Anwendungen oft notwendig. Ihr Entwickler (Kapitäne) habt ja die Entscheidungsgewalt; so nützt sie weise. Aber andere wegen ihrer Entscheidung zu kritisieren, fällt eigentlich außerhalb ihrer Kompetenz. Man wird meistens gute Gründe für Design Entscheidungen haben. Ich habe eben Meine. Obwohl ich ein bisschen mit C++ herum gespielt habe und mir gewisse Aspekte ganz klar nützlich sind, finde ich aber insgesamt, daß es mir im Kontext beschränkter uC wenig bringt mich vollkommen gescheit machen zu müssen, nur um C++ praktisch im Umfeld des uC benützen zu wollen, ohne viel Mühen herauszufinden, wie ressourceneffizient ich sie anwenden muß. Bei C und meinen bisherigen Erfahrungen, weiß ich genau, was ich tun muß oder nicht. In meinem Alter finde ich es wenig zielführend, unzählige Stunden aufwenden zu müssen, nur um in C++ efizient funktionieren zu können. Fakt ist, wenn man nicht andauernd das Neue übt, man es bald wieder vergisst. So gesehen bin ich mit einer Programmiersprache die ich gut kenne doch besser dran. Man mag das sehen, wie man will. Jeder soll doch so vorgehen wie es ihm vernünftig erscheint und tolerant anderen gegenüber sein, die eben anders denken und glücklich damit werden. Ich habe überhaupt nichts gegen C++, ausser, daß es mir zu viel Zeitaufwand verursacht, um es gründlich genug lernen zu können, so dass es mir auch etwas nützt. Ich brauche es im Kontext meiner Interessen nicht, und das, sollte genügen. Was nützt es, Anderen gegenüber abfällig zu sein, nur weil man denkt, man weiß es besser. Jeder hat für seine Denkweise und Logik seine Gründe. Da sollte man tolerant genug sein, Denkweisen Anderer zu respektieren. Dieser ganze Streit um den Bart der Sprachen, find ich wenig zielführend. Es gibt Leute, die bauen mit einfachsten Werkzeugen ein tolles Holzhaus in der Wildnis. Es gibt andere, die brauchen dazu eine Fabrik mit Werkzeugpark. Das gilt auch sinngemäß für uC Anwendungen. Gerhard
TL;DR Du beklagst einen Stellungskrieg zwischen den C und den C++-Jüngern? Normalerweise bin ich ja dafür zuständig, so etwas anzuzetteln ... doch aber nicht wirklich hier wegen meiner nur halb-ernst gemeinten Vorschläge ala Trotzdem bin ich der Meinung, dass jeder C-Entwickler von den vielen kleinen Goodies aus C++ profitieren kann. Das habe ich hier schon in ganz vielen Beiträgen auch beispielhaft unterlegt. Natürlich sind C und C++ unterschiedliche Programmiersprachen, C ist kein Subset von C++, und einige Details sind gefährlich unterschiedlich. Trotzdem schätze ich, das 90% der hier besprochenen Projekte mit Problemen, einfach als C++ kompiliert werden könnten, und man dann langsam ein paar Goodies aus C++ einfügen könnte. Man könnte also einfach versuchen, wenig zu ändern und doch viel zu profitieren.
Der ist ganz einfach zu lösen, indem man beide auf den Misthaufen der Geschichte wirft.
Hallo Wilhelm, Wegen TLDR, naja, ich habe nichts gehen C++ und verwende es auch in homöopathischen Dosen, wo es mir nützlich ist und intuitiv genug zum merken. However, ich habe keinen wirklichen Grund, mich als Gelegenheitsprogrammierer komplett einzuarbeiten, weil ich viele kritische Details wieder vergessen würde. Übung macht den Meister; aber wenn ich nur alle sechs Monate etwas durchziehe, reicht es doch nicht. Ich bin 69 und habe nicht mehr dasselbe Gedächtnis eines Jungspunds. Es geht nicht um die Philosophie von C++, sondern um die Praxis in meinem Kontext und habe überhaupt keine negative Einstellung C++ gegenüber, ich finde es einfach zu spezialisiert in Bezug auf den nächsten Abschnitt. Ich verwende einige uC Familien diverser Hersteller deren Werkzeuge nur C können und habe Gründe gewisse Teile oder Apps zu Portieren. Da müsste ich unter GCC C++ geschriebene Teile wieder auf C faktorisieren. Da bleibe ich lieber allgemein bei neutralen C wegen der Portabilität um es mir nicht anzutun. Ich muß auf meine vorhandenen Werkzeuge Rücksicht nehmen. Und PC Entwicklung jache ich nicht. Für embedded reichen mir meine Möglichkeiten. Gerhard
Nichts für ungut. Aber manche Deiner Kommentare finde ich wenig konstruktiv:-)
Ich schon. Meist ist es dann irgendwas in der folgenden Form:
Wichtig ist übersichtlicher Code. (Vor allem für den Fall, das ich da selber mal wieder ran muss....) Passt halbwegs hierher, denke ich, denn es geht auch um Endlosschleifen. :-) Geisterte gerade durch die WG14.
Gast
#7483527
Zusammenfassung:
also etwa,
Das ist die Zusammenfassung ausschließlich des Hans-Boehm-Papiers (und nicht etwa des ganzen Artikels).
Gast
#7483536
Was fehlt den aus dem Artikel zum Thema "unendliche ("for") Schleifen im C-Quelltext"? Es geht im Artikel halt um einiges mehr, und dieser Thread hier befasst sich ja nun auch an vielen Stellen mit (Un-)Schönheiten von C als solches. Daher sei die komplette Lektüre jedem angeraten. Man sollte natürlich immer im Hinterkopf behalten, dass der Artikel schlicht eine Meinung einer Person ist. Mit der kann man übereinstimmen oder auch nicht.
So wie ich das lese, wird argumentiert alle Endlosschleifen sollen UB sein, auch solche, die Seiteneffekte haben. Jedenfalls wird nicht auf Seiteneffekte der ersten Schleife verwiesen.
Das denke ich nicht. Endlosschleifen mit Seiteneffekten sind von der Argumentation nicht betroffen, denn Ausgangspunkt war die neue Formulierung in 6.8.5p6:
Cool. Bei vielen (den meisten?) Mikrocontroller-Programmen führt Terminieren dann wieder in eine Endlosschleife ;)
Beitrag #7483756 wurde von einem Moderator gelöscht.
Bei C liest sich das übrigens etwas anders:
Das heißt also, dass just der hier im Thread genannte Fall, egal ob "while(true)", "while(1)" oder "for(;;)" explizit als Endlosschleife implementiert werden muss. Also etwa sowas?
Geschweifte Klammern vergessen?
Liebe Mitforenten, ihr enttäuscht mich! Da verhunzt ein Newbie den Namen des lieben Peter https://de.m.wikipedia.org/wiki/Peter_Naur, und keiner weist ihn zurecht! LG, Sebastian
Von den fehlenden geschweiften Klammern abgesehen: auch sowas darf nicht wegoptimiert werden:
(Kann Sinn haben, wenn man anschließend alles in Interrupts, Threads etc. werkeln lässt.)
Ja.
Ich dachte, das sei die Aussage des obigen Zitats aus dem Standard. Der Compiler darf annehmen, dass diese Schleife terminiert (warum auch immer) und damit auch z.B. den Code, der danach kommt, ausführen. Seit C11 / C++11 und der Einführung des Memory-Models haben C und C++ etwas unterschiedliche Begriffe von forward-progress. Das führt dazu, dass endlos-Schleifen ohne Seiteneffekte in C++ UB sind und in C nicht. Bei trivialen endlos-Schleifen ist das sogar sichtbar. Ein Beispiel ist etwa folgendes:
Mit clang++ -O2 wird hier "xxx" ausgegeben! Die Schleife wird entfernt (UB), es bleibt im ASM das main-label, was dann auf derselbe Adresse wie unreachable liegt. Kurios, aber ein sehr schönes Beispiel dafür, was UB bedeuten kann.
Interessant. Gibt es auch ein Beispiel, wo dieser Unterschied zu einem Vorteil in C++ führt, bspw. in Form einer besseren Optimierung, die in C nicht möglich ist?
Nein, denn sie hat einen "constant controlling expression". Nur für Schleifen, die das nicht haben und nicht eine der nachfolgenden Aktionen ausführen (die ich nicht mit zitiert habe), darf der Compiler annehmen, dass sie irgendwann terminieren.
Was im Umkehrschluss heißt, dass C++ für MCUs eigentlich tabu ist, denn dort kann eine Endlosschleife ohne (sichtbare) Seiteneffekte essenziell sein.
Wer in seinem Code UB verwendet, ist selbst Schuld. Dies ist aber kein Problem der Sprache, sondern des Programmierers! Deswegen: natürlich ist C++ (genauso wie C) absolut gut für MCU geeignet. Auch in C kann ich UB produzieren (ja: nicht durch dieses Konstrukt), aber deswegen die Sprache C als ungeeignet abzustempeln, machst Du ja auch nicht. Formell hat ein C++-Programm, was mit einer leeren Endlos-Schleife geschrieben ist, und deswegen ISRs enthalten muss, wenn es irgendetwas sinnvolles tun soll, noch ein weiteres Problem: es ist nämlich strenggenommen kein valides C++ Programm. Zwar existieren im C++-Standard Signal-Handler, die per signal() registriert werden, und man könnte sie zu ISTs ähnlich betrachten, aber: ähnlich ist nicht gleich im Sinne des Standards. Also anders herum formuliert: wer also ein C++-Programm durch die Verwendung von ISRs als nicht konformes Programm darstellt, der sollte schon wissen was er tut, und da ist diese Endlos-Schleife das kleinste Problem.
Eine praktischere Anwendung für eine Endlos-Schleife ist z.B. "warten auf den Watchdog Reset". Das kann man auch in einem ansonsten "normalen" C++-Programm gebrauchen. Deswegen bleibt das Programm doch valide. Womit könnte man so eine Endlos-Schleife norm-konform ersetzen?
Geht nicht: ein C++-Programm ohne Seiteneffekte ist schlicht invalide.
Aber wie gesagt: die Watchdog-Exception oder -Reset ist auch etwas, was so im C++-Standard nicht betrachtet wird.
Es ist der Umkehrschluss: wenn Endlos-Schleifen zu einem invaliden C++-Programm führen, dann folgt daraus, dass ein valides C++-Programm kein Endlos-Schleifen enthält. Sprich: der Compiler kann annehmen, dass jede Schleife terminiert! Er muss es nicht mehr beweisen, was ja das Halte-Problem wäre ;-) Und damit kann er bspw. aufeinanderfolgende Schleifen zu einer zusammen fassen. Und das ist ein Performance Vorteil (im Paper von H. Boehm war ein Beispiel).
Dazu noch ein Beispiel:
Der C++-Compiler (g++ -O3) produziert daraus ein simples
Und der C Compiler (gcc -O3):
Hat der C++-Compiler die Collatz-Annahme bewiesen? Wohl kaum. Es nimmt einfach an, dass die Schleife bei i == 1 terminiert.
Beitrag #7484365 wurde von einem Moderator gelöscht.
wird zu
Vielleicht sieht man es so besser?
Warum? Das ändert doch nichts. Wo die 42 herkommt hat doch nichts damit zu tun, dass der Compiler aus dem "i |= 1" im Schleifenkopf schlussfolgert, dass die Schleife terminiert und i danach den Wert 1 hat.
Nur dass, im Gegensatz zu C++, das analoge C-Programm eben gerade kein undefined behaviour zeigt. Dort ist die Endlosschleife mit konstanter Schleifenbedingung legal und definiert. Damit ist es in der Tat ein Problem der verwendeten Sprache – auch ohne eine explizite Endlosschleife, wie sie bspw. für Rust genannt worden ist.
Ich weiß ja, dass Du lieber Haskell statt C++ magst. Aber nochmal: wenn ein Programmierer nicht auf die Unterschiede zwischen Programmiersprachen achtet, und damit in der einen Sprache UB produziert, ist das nicht Problem der Sprache, sondern des Programmierers. Für die ISR-only Fraktion wäre ggf.
ein Möglichkeit. In C++ garantiert UB-frei.
Beitrag #7484462 wurde von einem Moderator gelöscht.
nö
Nur, falls nicht gerade jemand sleep irgendwie so definiert hat:
Ich bleibe dabei, dass ich die C++-UB an dieser Stelle für eine eher nutzlose und gefährliche Geschichte halte. Da es in C kein UB ist, gibt es eigentlich auch keine wirkliche Rechtfertigung dafür.
Weil manche ein fehlendes = moniert haben :), hier eine bessere Version:
Da hat man dann auch eine schöne Abreißkante beim Typenraddrucker, denn der Code danach wird ja nicht ausgeführt. Oder gerade doch wenn man den obigen Ausführungen folgen sollte...
Kann es sein daß der Compiler einfach erkennt daß die Funktion nur mit einer Konstante aufgerufen wird? Wenn das Argument ein Nutzerinput ist, was dann? Das Microsoft C++ wirft die Funktion dann jedenfalls nicht raus.
Nein. Probiere
Hier ist noch ein (zugegebenermaßen etwas spezielles) Beispiel, wo die Behandlung von Endlosschleifen nach dem C-Standard vorteilhaft sein kann:
Ein pfiffiger Mathematiker möchte herausfinden, ob in der (unendlichen) Collatz-Folge mit dem Startwert 42 die 7 vorkommt. Natürlich kann man auch ohne Computer leicht beweisen, dass dies nicht der Fall ist. Da der Mathematiker aber möglichst zielgerichtet vorgehen und möglichst wenig seiner Denkzeit investieren möchte, beschließt er, vorab mit Hilfe des Computers eine erste Vermutung zu generieren. Er nimmt also das von Wilhelm gepostete Programm und ersetzt darin die Zeile
durch
Er kompiliert das Programm als C-Programm und lässt es maximal 5 min laufen. Es gibt nun zwei Möglichkeiten:
In beiden Fällen hat er zwar nur eine Vermutung, aber so eine Vermutung kann bei der anschließenden formalen Beweisführung helfen, Sackgassen zu vermeiden und damit Denkzeit zu sparen. Mit C++ funktioniert diese Vorgehensweise wegen des UB nicht so ohne weiteres. Natürlich kann man in die Schleife irgendeinen Seiteneffekt (bspw. den Zugriff auf eine volatile-Variable) einbauen. Das macht aber den Code langsamer, so dass innerhalb der 5 min weniger Iterationen ausgeführt werden, was wiederum die resultierende Vermutung schwächt.
Du solltest allerdings bedenken, dass auch bei C der Compiler genau diese Optimierung durchführen darf: Nochmal aus dem C-Standard:
In meiner obigen Funktion ist genau so eine Iteration drin. Die Bedingung ist keine constant-expression und die Berechnung enthält keine Seiteneffekte. Der Compiler nimmt an, dass sie terminiert: für i == 1 in meinem Fall oder i == 7 in Deinem Fall. Also hier steht bzgl. der mögl. Optimierung kein Unterschied zwischen C und C++. Und der Clang / Clang++ machen das auch gleich. Beim GCC schein es ein missing-optimization-bug zu sein. Daher stimmt Deine obige Aussage nur für einen Compiler, der diese mögl. Optimierung nicht nutzt.
Stimmt. Ich bin irrtümlicherweise (und ohne lange darüber nachzudenken) davon ausgegangen, dass du mit dem Collatz-Beispiel die Unterschiede zwischen den beiden Standards und nicht nur die Unterschiede zwischen clang++ und gcc aufzeigen wolltest. Ich denke, die ganze Verwirrung bzw. Unklarheit zwischen WG14 und WG21 liegt in folgendem:
Aus 1) folgt, dass in C++ Endlos-Schleifen ohne Seiteneffekte UB sind (nicht-valide), und die Fußnote sagt explizit, dass dieses zu Optimierungszwecken genutzt werden kann. In dem hier gezeigten Beispiel besteht die Optimierung daraus, anzunehmen, dass die Schleife auch ohne Beweis terminiert. Bei der trivialen Endlos-Schleife for(;;) {} kann der Compiler trivial beweisen, dass die Schleife nicht terminiert, daher ist sie UB, und darf entfernt werden. Aus 2.2) folgt auch für C wie in C++ die Optimierung der Schleife wie in 1) Aus 2.1) folgt allerdings, dass ein triviale Endlos-Schleife for(;;){} kein UB ist. Bis C++03 War in C++ die Formulierung unter 1) nicht drin. Damit war auch in C++03 die triviale Endlos-Schleife kein UB. In C99 war 2.2) nicht drin, damit hatte der C-Compiler diese Optimierungsmöglichkeit nicht. Das ist vllt der Grund für den GCC missing-optimization-bug. Es gibt jetzt Bestrebungen (so wie ich das beobachte), die Formulierungen zu vereinheitlichen.
Genau diese Mentalität "ist UB, also darf der Compiler eh machen, was er will" ist ja, was das von mir referenzierte Paper insgesamt kritisiert: "Prioritize Performance over Correctness".
Absolut, und das gilt für beide Sprachen C und C++! (Manchmal in der Diskussion hatte ich den Eindruck, dass sei mal wieder nur ein C++ Problem) Blöderweise gibt es Endlosschleifen ohne vom Compiler erkennbare Nebeneffekte, die diese aber in Hardware haben. Ein Beispiel ist der Weg, wie AVRs sich selbst zurücksetzen: Watchdog aktivieren, Interrupts ggf deaktivieren, und dann for(;;){}. Wäre dann schon gut, wenn der Compiler das nicht wegoptimiert. Ähnlich läuft es bei Programmen, die sämtliche Aktivitäten in Interrupts erledigen.
Den Watchdog aktivieren hat mit der Schleife aber nichts zu tun.
Ja klar, ich hatte oben schon ein Lösung dargestellt.
Dann sind wir ja mal einer Meinung. :-)
Ist es eher zufällig in diesem ganz speziellen Fall, ansonsten sind sie sich ja in vielen sehr ähnlich. Hallo, jetzt habt ihr mich völlig vom Glauben abgebracht. Es hieß immer Seiteneffekte sind nicht gut und müssen vermieden werden. Jetzt soll man Seiteneffekte einbauen damit es nicht UB ist? Ich komme ehrlich gesagt nicht mehr mit. Das kleinste C/C++ Programm lautet
steht in allen Büchern. Das ist aber deshalb inkorrekt, weil es einen Rückgabewert liefern muss, jedoch keinen erzeugt. Das war allerdings jetzt gar nicht das Problem. :-)
Perfekt. Wo ist das Problem?
Nein. main() ist besonders, dass es implizit 0 zurück gibt.
OK, das war mir nicht bewusst.
Der Begriff Seiteneffekt ist nicht genau definiert, in diesem Kontext bedeutet es eher "observable effect", entsprechend den Aktionen, die die Standards erwähnen.
main() hat auch in C mehrere Signaturen, ist also gewissermaßen implizit überladen.
Ja, aber (im hosted environment) geben sie alle "int" zurück, nur die Parameterliste kann entweder (void) sein (was in C nicht identisch zur leeren Liste in Veits Beispiel ist) oder (int, char **).
gehört nicht zur Signatur
... und eine beliebige weitere! z.B int main(int argc, char *argv[], char *envp[]) Und als freestanding muss es noch nicht mal main() sein.
WIMRE aber erst ab C99.
Ist aber im Standard vorgeschrieben.
Korrekt, aber freestanding schaltet allerlei Optimierungen ab, die Annahmen bezüglich der Standardbibliothek treffen. Bspw. kann der Compiler dann "strlen("foo")" nicht mehr einfach durch die Konstante 3 ersetzen. Daher meide ich das persönlich selbst in Umgebungen, die eigentlich den Charakter von "freestanding" haben (wie MCUs).
Es hat keine Seiteneffekte, ist also UB in C++. Oder gibt es noch ne Regel, dass dieser Fall nicht UB ist?
Es terminiert.
Wo steht das? Was hat das mit main() zu tun? Ist das eine vorgeschriebene Optimierung wie bspw. copy-elision oder NRVO?
Dein Beispiel ist UB, da auf r ohne Initialisierung zugegriffen wird. Da kann der Compiler machen was er will. Ich hab mal mit godbolt.org und clang 16.0.0 x86-64 folgendes übersetzen lassen:
und das Assemblerlisting zeigt daß er die Funktion so implementiert wie sie geschrieben steht.
Ja wie sieht denn eine leere Endlosschleife in C++ nun aus? Im Standard stehen ja nur Brainfuck-Argumente was nicht geht. Aber wie geht es denn nun? z.B. eine lokale volatile Variable zu setzen wäre zwar konform, aber absoluter Overkill weil Compiler solche Variablen nicht in Registern anlegen sondern im Frame! Man brauch also nicht nur einen Frame, sondern falls er nicht wegoptimiert werden kann sogar noch einen Frame-Pointer. Beispiel: avr-g++. Und Dinge wie __asm volatile ("":); sind nicht durch den Standard abgedeckt und nicht portabel.
-O3 vergessen?
Geht nicht, soweit ich weiß (s.o.).
Das ist es keine "leere" Endlos-Schleife mehr, und sie hat Seiteneffekte. Wie gesagt, würde ich mir nicht so große Gedanken machen, weil auch ISRs nicht vom Standard gedeckt sind. Also ein C++-Programm mit ISRs ist einfach nicht Standard-konform (s.o. hatte ich schon geschrieben), damit erübrigt sich die Frage nach der Schleife.
Jetzt mal Butter bei die Fisch und nicht immer drumrumreden. Mach's mal explizit! Was kommt am nächsten an wheil(1); ran? Ideralerweise so, dass auf Asm-Ebene nur ne leere Schleife bleibt.
Sind die jetzt auch UB???
Kannst Du nicht lesen?
Nein, aber sie existieren einfach nicht.
Non-local with static storage
Doch. Aber ich find's einfach nicht. Nur den Beitrag
der aber nicht auf die Lösung verweist. Und "oben" sind > 300 Beiträge. Vielleicht magst du den Beitrag mit der Lösung nochmal verlinken. Oder zitieren, wird ja nicht mehr als 1 Zeile sein.
Das ist aber schon eine interessante Auslegung. Er kann beweisen, dass die Schleife nie verlassen wird, und deshalb kann er sie einfach rauswerfen. Klar ist das bei UB nicht verboten, aber die Argumentation wirkt trotzdem etwas komisch. Denn so macht der Code ja das exakte Gegenteil von dem, was jemand, der diese Regel nicht kennt, erwarten würde.
Ist auch eine eher obskure Regel.
Ich denke, es ist eher umgekehrt: Bei hosted ist dem Compiler explizit erlaubt, die Annahme zu treffen, dass sich alle Standardfunktionen genau so wie im Standard definiert verhalten und auf der Basis zu optimieren. Ich wüsste aber nicht, dass es ihm bei freestanding verboten wäre, Annahmen über mitgelieferte Funktionen zu treffen.
Nein. Globale Variablen werden implizit mit 0 bzw. default-initialisiert.
Das sehe ich anders. Was hab ich davon, zu sagen: "Ja, wegen der ISR ist das Programm sowieso nicht konform, also ist auch egal, was bei der Schleife passiert". Ich muss auf einem µC halt auch ISRs schreiben, und die funktionieren auch wie gewünscht, die Schleife aber auf Grund dieser Standard-Regel nicht.
Tatsächlich, mit -O3 wird es dann auch im clang wegoptimiert, kopfkratz...
Hast Recht wird mit 0 initialisiert..., aber trotzdem konstant. Weil ohne Speicheradresse ändert da auch das volatile nichts.
Und? Ein volatile-Zugriff reicht aus, und das ist einer. Was drin steht oder ob sich der Wert ändert, spielt keine Rolle.
?
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. Compiliere einfach mal mit dem Compiler deiner Wahl mit -ffreestanding und -fhosted:
Dass main() in einem freestanding environment einfach gar nicht definiert wird (und nicht einmal existieren muss), während es in einem hosted environment halt die beiden genannten Prototypen mit Rückkehrwert "int" haben soll (oder eben "implementation-defined").
Verstehe ich nicht, etwas verworren. Alle Funktionen, die im Set der verpflichtenden Funktionen der Freestanding Variante vorhanden sein müssen, müssen wie beschreiben arbeiten. Allerdings: <cstring> gehört gar nicht zum Freestanding set.
Genau, Du benutzt etwas, was nicht dazu gehört. Insofern muss sich der GCC gar nicht darum kümmern und kann deswegen auch gar keine (Frontend)-Optimierungen ausführen.
Ja, siehe oben:
Moin, ich möchte ungern die gesellige Runde stören. Nur verstehe ich aktuell gerade nicht warum etwas UB sein soll wenn die gelebte Praxis seit Jahrzehnten es genauso programmiert. int main() { while(1) bzw. for(;;) { ... sinnvoller Code ... } } Würde ja bedeuten das entweder der Standard völlig an der Praxis vorbei lebt oder der C++ Compiler sich nicht an den Standard hält oder noch anders. Sonst wären ja alle Programme für µC UB. Kann ja nicht sein. Das meinte ich mit, ich falle vom Glauben ab. Aber keine Sorge ich bin nicht gläubig.
Du kannst aber
verwenden.
Das hängt stark davon ab, was ... sinnvoller Code ... ist. Moin, Mir schwirrt schon der Kopf. Da war ich jahrzehntelang ein glücklicher und zufriedener Programmierer. Dann kamt ihr; ihr, die jetzt meine heile Welt in Schutt und Asche gelegt habt und ich mich am Boden zerstört vorfinde:-) was nu? Am Anfang konnte man sich ja nur an die Herstellerhandbücher halten und die schwiegen sich über die hier diskutierten Feinheiten völlig aus. Die konzentrierten sich eher auf bewährte Programmierpraxis anstatt auf graue Theorie in verstaubten Compiler und Sprachenstandards herumzustöbern. Abgesehen davon gelten im embedded Bereich andere Berücksichtigungen um im uC Bereich praxisgerecht zu sein. Z.B. ein return für main() hat da ja keinen Sinn. In Systemen mit BS, gefordert. Es funktionierte ja immer wie vorgegeben. Ich befasse mich auschließlich mit embedded. Ist es dies alles in 99% aller Anwendungsfälle wert? Irgendwie sollte embedded praxisnahe sein. Gerhard Habe gerade mal den folgenden Code mit g++ (64bit Linux) und auch avr-g++ übersetzt. Sowohl ›while‹ als auch (alternativ) ›for‹ erzeugen übrigens präzise den gleichen Assembler-Code.
Ergebnis:
Was mache ich denn nur falsch, oder besser gefragt, warum funktioniert das hier problemlos und zwar ganz genau so wie man es erwarten würde?
Weil der GCC das so macht. Es besteht keine Pflicht den Code mit UB zu entfernen.
Aha, interessant. Eine nicht ganz unwichtige Information. Das heißt andere C++ - Compiler könnten sämtliche ISRs ungefragt weg optimieren, weil die ja wohl auch - wie weiter oben zu lesen - UB sind. Ein - hmmm, sagen wir mal - interessanter Ansatz. Wenn ihr im Rahmen der Diskussion schlussendlich feststellt, dass es zwar theoretisch möglich ist, nicht-triviale C- oder C++-Programme zu schreiben, die ausschliesslich perfekt definiert (und korrekt) arbeiten, nicht aber praktisch, dann seid ihr schon dicht in der Realität angekommen. ;-)
UB ist Verhalten, für das der Standard absolut keinerlei Vorgaben macht. Es gibt damit grundsätzlich keine Verpflichtung für den Compiler, irgendetwas zu tun oder nicht zu tun.
Oben ist ausdrücklich zu lesen, dass sie im Standard schlicht gar nicht existieren. Die Compiler-Unterstützung dafür liegt also so oder so außerhalb des Standards. Da ISRs oft keine ganz normalen Funktionen sind, gibt's gar nicht erst einen Standard-Weg, sie überhaupt zu definieren. Und wenn ein Compiler schon eine solche nicht-Standard-Erweiterung anbietet, wird er das natürlich so tun, dass sie auch brauchbar ist.
Es müsste eher ... sinnloser Code ... heißen, denn sobald der Code irgendeine reale Auswirkung hat, gilt das nicht mehr.
Beim Cortex-M sind ISRs normale Funktionen ohne irgendwelche Sonderlocken wie Nicht-Standard-Erweiterungen. Damit können die also alle weg. ;-)
Ist aber nicht das selbe wie strlen. length("1""\0""2""\0""3""\0\0"); // -> 6 strlen("1""\0""2""\0""3""\0\0"); // -> 1 Hier noch eine Variante einer endlos schleife, die Optimierungen braucht:
Ohne Optimierungen läuft der stack irgendwann über, aber mit können Compiler daraus eine richtige Schleife machen, dank Tail calls.
Weil WG21 das so festgelegt hat und seither for(;;){} Undefined Behaviour ist. Was ich vermisse, ist dass der aktualisierte Sprachstandard sowas wie Best Practices" nennt, wie das Verhalten des ehemals gültigen Codes mit den aktualisierten Mitteln erreicht werden kann. Und hier im Thread wird auch drumrum geredet; wie so oft. Es werden einem Buzzwords oder Teile des Standards um die Ohren gehauen, aber wie genau etwas umgesetzt werden kann... da wird gekniffen.
Wäre nicht das erste mal, dass Bedürfnisse von Bare Metal Plattformen ignoriert werden. Früher[tm] wäre /* Empty Body */ unter "sinnvollen Code" gefallen, weil es Anwendungen dafür gibt. Mit akltellem C++ ist es kein sinnvoller Code mehr da UB. Aber was soll man stattdessen nehmen wenn man den Effekt des alten for(;;){} erreichen will?
oder der C++ Compiler sich nicht an den Standard hält oder noch
Wie werden sie dann aufgerufen? Auch wenn die ISR an sich einfach als Standard-Funktion definiert werden muss, muss der Compiler trotzdem irgendeine Erweiterung haben, damit sie beim Interrupt auch zur Ausführung kommen. Ein Compiler, der sie dann wegoptimiert, wäre zwar in der Hinsicht standardkonform, aber für µC-Entwicklung halt nicht zu gebrauchen.
Typischerweise zwei zusätzliche Instruktionen. Wenn die nicht mehr in den Flash passen, wirst du eh bald ein Problem haben.
Über die Vektortabelle. Auch diese ist aber ein ganz normales C-Array, das lediglich an einer bestimmten Stelle im Speicher stehen muss. Cortex-M ist ja explizit so designt worden, dass man keine Assembler-Magie mehr benötigt – wenngleich es manche Hersteller bevorzugen, den Startup-Code immer noch in Assembler zu meißeln. Bei Atmels SAMDxx etc. dagegen ist der Startup-Code in C. Üblicherweise werden die Funktionen der Vektortabelle zwar jenseits des Standards als "weak" deklariert, aber das dient lediglich der Bequemlichkeit, dass man auf diese Weise mit einer vorgefertigten Tabelle arbeiten kann und nicht jede Applikation ihre eigene selbst bauen muss. Technisch könnte man auch alles "pure C" selbst schreiben.
Zum Beispiel indem IRQ-Vektoren initialisiert werden. Dass IRQ-Vektoren mehr oder weniger hart verdrahtet sind wie bei avr-gcc ist eher unüblich. Eher üblich wäre, ne IRQ nen indirekten Sprung zu nem Signal-Handler ausführen zu lassen. Und der Handler (bzw. dessen Adresse) wird vir dessen Verwendung eben irgendwo eingetragen.
Bordmittel reichen aus, z.B. Funktionsadresse irgendwo eintragen. Oder <signal.h>.
Es ist mehr. GCC legt auto volatile Variablen im Frame an, nicht in Registern. Es muss also auch ein Frame allokiert werden und zusäzulich ein Frame-Pointer (der nicht wegoptimiert werden kann). ...ok, bei avr-g++ sind's nur 4 Instruktionen mehr, ist jetzt nicht super tragisch. Aber es ist einfach auch hässlich, nen Code hinschreiben zu müssen der mehr macht als nix.
Heutzutage will man Strom sparen, also muss man das der Hardware irgendwie sagen. Und schon ist die Schleife nicht mehr leer. Was uns zum nächsten Problem bringt :) Wenn man dafür kein Bit setzen kann, braucht man einen Maschinenbefehl wie WFI. Was sagt der Standard denn dazu?
Garnichts. Im Standard gibt's nix wie WFI, Sleep, SFRs oder "Strom sparen".
Das meinte ich nicht. Der Aufruf wird initial nicht durch in C++ geschriebenen Code ausgelöst, sondern durch interne Hardware des µC. Und damit liegt er außerhalb des Standards.
Ein Standard-konformer Compiler kann von einem gewissen Codefluss ausgehen. Und da ist es nicht vorgesehen, dass quasi aus dem Nichts heraus mitten in der Ausführung spontan irgendeine Funktion aufgerufen wird, obwohl an der Stelle im Code kein Funktionsaufruf steht.
Dann einfach static machen. Braucht dann halt noch ein Byte im RAM, dafür keinen Stackframe.
Ich habe ein ldi vor und ein std in der Schleife gesehen, zumindest bei -Os. Natürlich habe ich aber nicht int, sondern uint8_t genommen. Bei -O3 scheint er lustigerweise ein loop-Unrolling zu machen, aber nur wenn die Variable nicht static ist. Mit -O3:
Mit -Os:
Es ist auch schon hässlich, Code hinschreiben zu müssen, dessen einzige Aufgabe es ist, eigentlich nichts zu machen. Bevor hier manche Schnappatmung bekommen ...
Allerdings würde ich mich mal wirklich dafür interessieren, in welchem Projekt (mehr als Küchentisch-Hobby) diese Schleife so vorkommt.
Und außerdem ist es vollkommen egal, mit welchem Unsinn die CPU in der Endlos-Schleife Ihre Zeit verbringt. Also wenn Euch
nicht passt, dann nehmt
Und das noop() könnt ihr nach Eurem Gusto ausgestalten:
Dadurch wird die Latenz bis zur ISR auch nicht schlechter.
Doch, der Code ist unbrauchbar weil man sich nicht darauf verlassen kann. Oder verwendest du UB in deinen Projekten, und kontrollierst nach jedem Compilerlauf, ob das generierte Assembly noch deinen Wünschen entspricht?
Es zeigt garnix. Insbesondere zeigt es nicht, dass der Code verwendbar wäre (da UB). Es scheint auch kein Schalter (wie etwa für Signed Overflow) zu geben, der die alte Semantik von for(;;) herstellt.
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. Beispiel 2: Eine Applikation, die all ihre Aufgaben in ISRs erledigt. Am Ende von main, nach Konfiguration aller IRQs, steht dann eine leere Endlosschleife. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|