Hallo zusammen. Um eine switch-Anweisung zu vereinfachen, würde ich gerne eine Funktion statt einer Variablen einfügen. Bsp.
1 | |
Was spricht dagegen?
|
Anzeige
|
switch(Funktion()) möglich?Hallo zusammen. Um eine switch-Anweisung zu vereinfachen, würde ich gerne eine Funktion statt einer Variablen einfügen. Bsp.
Was spricht dagegen?
Gast
#5419179
__Son´s B. schrieb: > Was spricht dagegen? Das kommt drauf an, was das Handbuch der von dir verwendeten Programmiersprache dazu sagt. W.A. schrieb: > verwendeten Programmiersprache Programmiersprache ist C. Compiler AtmelStudio 7. Wenn es funktioniert, wäre es besonders "unsauber" programmiert?
Gast
#5419189
__Son´s B. schrieb: > Wenn es funktioniert, wäre es besonders "unsauber" programmiert? Ja, besser testbar und einfacher zu debuggen ist die Variante mit einer Hilfsvariablen. Ein gut optimierender Compiler erkennt die Verwendung und wird die Variable im 'Release' rauswerfen. => Varibale kostet nix und macht es einfacher.
Gast
#5419195
Funktioniert prinzipiell, ist aber kein sauberer Programmier-Stil. good coding schrieb: > __Son´s B. schrieb: >> Wenn es funktioniert, wäre es besonders "unsauber" programmiert? > > Ja, besser testbar und einfacher zu debuggen ist die Variante mit einer > Hilfsvariablen. Begründung? Peter S. schrieb: > Funktioniert prinzipiell, ist aber kein sauberer Programmier-Stil. DANKE, für die konstruktiven Rückantworten! Peter S. schrieb: > Funktioniert prinzipiell, ist aber kein sauberer Programmier-Stil. Begründung?
Gast
#5419207
Ich sehe da auch keinen Grund für.... Klar kann man eine unnötige Variable einführen. Aber irgendwie schöner, wird da nix von.
Gast
#5419219
Wilhelm M. schrieb: > Begründung conditional breakpoint, Variable im Debugger verändern, ..., typesicher, ... good coding schrieb: > Wilhelm M. schrieb: >> Begründung > > conditional breakpoint, Variable im Debugger verändern, ..., typesicher, > ... In diesem switch-stmt? Wozu? Typ-sicher?
Gast
#5419225
Wilhelm M. schrieb: > Peter S. schrieb: >> Funktioniert prinzipiell, ist aber kein sauberer Programmier-Stil. > > Begründung? Es erschwert das Debuggen, als dass (nicht überall) ein Unterbrechungspunkt nicht zwischen Auswertung des Selektors und Sprung zur Marke gesetzt werden kann. Ein ordentliches
erfüllt seinen Zweck. ist kein wesentlicher Mehraufwand. Erzeugt keinen Overhead bei Optimierung und hat keine [versteckten] Nebeneffekte.
Gast
#5419232
Da man bei Hochsprachen sich vom Wissen was der Compiler hinter den Kulissen tut trennen sollte, sind mir Sprachen lieber welche sinngemäss auch folgendes erlauben:
Maxx schrieb: > Wilhelm M. schrieb: >> Peter S. schrieb: >>> Funktioniert prinzipiell, ist aber kein sauberer Programmier-Stil. >> >> Begründung? > > Es erschwert das Debuggen, als dass (nicht überall) ein > Unterbrechungspunkt nicht zwischen Auswertung des Selektors und Sprung > zur Marke gesetzt werden kann. Das ist wohl Geschmackssache, ob ich einzelne unbedingte BPs oder einen bedingten BP setze. > > Ein ordentliches >
> > erfüllt seinen Zweck. ist kein wesentlicher Mehraufwand. > Erzeugt keinen > Overhead bei Optimierung Was für einen Overhead? > und hat keine [versteckten] Nebeneffekte. Wo waren die Seiteneffekte? Programmiersprachentheaterintendant schrieb: > Da man bei Hochsprachen sich vom Wissen was der Compiler hinter den > Kulissen tut trennen sollte, sind mir Sprachen lieber welche sinngemäss > auch folgendes erlauben: >
Nehme aber an, dass es sich um C handelt ... da gehts dann nicht.
Gast
#5419241
Wilhelm M. schrieb: > Maxx schrieb: >> Wilhelm M. schrieb: >>> Peter S. schrieb: >>>> Funktioniert prinzipiell, ist aber kein sauberer Programmier-Stil. >>> >>> Begründung? >> >> Es erschwert das Debuggen, als dass (nicht überall) ein >> Unterbrechungspunkt nicht zwischen Auswertung des Selektors und Sprung >> zur Marke gesetzt werden kann. > > Das ist wohl Geschmackssache, ob ich einzelne unbedingte BPs oder einen > bedingten BP setze. Du kannst keinen einzelnen unbedingten oder bedingten BP setzen (es ist die gleiche Anweisung. Einige Umgebung erlauben keine multiplen BP pro Zeile) , es sei denn du setzt den BP innerhalb der func(). Dann aber feuert der auch bei anderen Aufrufen von func() .... > >> >> Ein ordentliches >>> var_t selector = func(); >> switch (selector) >> { >> > >> erfüllt seinen Zweck. ist kein wesentlicher Mehraufwand. >> Erzeugt keinen >> Overhead bei Optimierung > > Was für einen Overhead? Zuweisung einer Variablen. Unoptimiert wird dafür Speicher reserviert, beschrieben und danach wieder ausgelesen. > >> und hat keine [versteckten] Nebeneffekte. > > Wo waren die Seiteneffekte? func() macht etwas. Du hast keine direkte Einsicht in dessen Inhalt. Wird dabei ein Zusatnd gewechselt? Dies ist nicht offensichtlich. Bei dem (ebenfalls schlechtem Stil)
fällt das wenigstens auf.
Gast
#5419242
> Ein ordentliches >
passt so schön zu
O_o Programmiersprachentheaterintendant schrieb: >> Ein ordentliches >>
> > passt so schön zu >
> > O_o Ja ;-) Wenn schon, dann:
Maxx schrieb: > Wilhelm M. schrieb: >> Maxx schrieb: >>> Wilhelm M. schrieb: >>>> Peter S. schrieb: >>>>> Funktioniert prinzipiell, ist aber kein sauberer Programmier-Stil. >>>> >>>> Begründung? >>> >>> Es erschwert das Debuggen, als dass (nicht überall) ein >>> Unterbrechungspunkt nicht zwischen Auswertung des Selektors und Sprung >>> zur Marke gesetzt werden kann. >> >> Das ist wohl Geschmackssache, ob ich einzelne unbedingte BPs oder einen >> bedingten BP setze. > > Du kannst keinen einzelnen unbedingten oder bedingten BP setzen (es ist > die gleiche Anweisung. Will ich doch auch gar nicht ;-) > func() macht etwas. > Du hast keine direkte Einsicht in dessen Inhalt. Wird dabei ein Zusatnd > gewechselt? Das ist (könnte sein) auch bei der ursprünglichen Variante so.
Gast
#5419254
Ich denke auf Troll-Level brauchen wir nicht weiterzureden. Man kann auch aus nem Trog fressen und wird nicht verhungern. Der Stil wird jedoch in den wenigsten Kulturen als gut gelten. Ich bin raus. Ciao
Gast
#5419257
Programmiersprachentheaterintendant schrieb: > sind mir Sprachen lieber welche sinngemäss > auch folgendes erlauben:switch(egal) { > > case( function( ... )): > > ... > > } Wann wird function aufgerufen, wenn es mehrere Cases gibt? Immer alle? In welcher Reihenfolge? Wird der Rest ausgelassen, sobald ein Case zutrifft? Das ist sehr schwer lesbar und nachvollziehbar. Nein danke.
Gast
#5419258
Wilhelm M. schrieb: > Will ich doch auch gar nicht ;-) Du willst deinen Code nicht testen? Ok, dann mach mal weiter so. :-((( good coding schrieb: > Wilhelm M. schrieb: >> Will ich doch auch gar nicht ;-) > > Du willst deinen Code nicht testen? > Ok, dann mach mal weiter so. :-((( Testen mache ich nicht mit dem Debugger, ich schreibe Test-Fälle ... lies Dir den Beitrag nochmal genau durch.
Gast
#5419264
__Son´s B. schrieb: > Was spricht dagegen? Da spricht nichts gegen, es ist sauber, klein, effektiv und lesbar. Ich verstehe nicht, wieso einem Anfänger (der auch höflich fragt) das um die Ohren gehauen wird, nur weil Fälle denkbar sind, in denen eine getrennte Variable besser wäre? Und wer sinngemäß auch "case( function( ... ))" wünscht, macht ein Fass auf, dass den Bereich der Imperativen Programmiersprachen verlässt. Denn bei denen würde das (im gegensatz zu Bereichen oder Masken) umfangreiche defizile Definition erfordern, wenn und in welcher Reihenfolge diese Funktionen denn aufgerufen würden.
Gast
#5419266
Wilhelm M. schrieb: > ich schreibe Test-Fälle Das wird durch eine Hilfsvariable erleichtert! Maxx schrieb: > Ich bin raus. Ciao Du hast recht, sollen die Hobby-Bastler ihre Zeit bei erschwerter Ferhlsuche vergeuden. Auch raus ... good coding schrieb: > Wilhelm M. schrieb: >> ich schreibe Test-Fälle > > Das wird durch eine Hilfsvariable erleichtert! Wie schreibst Du denn Deine Testfälle? Achim S. schrieb: > __Son´s B. schrieb: >> Was spricht dagegen? > > Da spricht nichts gegen, es ist sauber, klein, effektiv und lesbar. Sehe ich genauso. Falls es C++ sein sollte, kannst Du mit einem init-stmt im Bedingungsteil den Scope von ggf. benötigten Bezeichnern auf das switch-stmt einschränken. Was dann ein Vorteil wäre.
Gast
#5419282
> Wann wird function aufgerufen, wenn es mehrere Cases gibt? Immer alle? > In welcher Reihenfolge? Wird der Rest ausgelassen, sobald ein Case > zutrifft? Das steht in der Sprachspezifikation geschrieben, wo hoffentlich nicht so oft wie in C et al. "behaviour is left to the implementor" vorkommt. Die selben Fragen stellen sich bei If-Kaskaden. Also wozu überhaupt ein so eingeschränktes "switch"? Das geht mit Arrays genausogut. > Das ist sehr schwer lesbar und nachvollziehbar. > Nein danke. U.U. nicht Schwieriger als C et al.
Gast
#5419284
Maxx schrieb: >> Was für einen Overhead? > > Zuweisung einer Variablen. > Unoptimiert wird dafür Speicher reserviert, beschrieben und danach > wieder ausgelesen. Sinnvollerweise wird der Compiler soetwas in ein Register packen. Dann wird deswegen gar nicht im Speicher rumgemacht ... Wer in seinem Programm das Timing über Taktzyklen macht, sollte allerdings tunlichst wissen, was er tut.
Gast
#5419290
Achim S. schrieb: > Und wer sinngemäß auch "case( function( ... ))" wünscht, macht ein Fass > auf, dass den Bereich der Imperativen Programmiersprachen verlässt. Denn > bei denen würde das (im gegensatz zu Bereichen oder Masken) umfangreiche > defizile Definition erfordern, wenn und in welcher Reihenfolge diese > Funktionen denn aufgerufen würden. PHP tut das so.
Hat seines Reiz!
Gast
#5419294
good coding schrieb: >> ich schreibe Test-Fälle > > Das wird durch eine Hilfsvariable erleichtert! Woher willst du das wissen?
Gast
#5419299
Arduino F. schrieb: >> Und wer sinngemäß auch "case( function( ... ))" wünscht, macht ein Fass >> auf, dass den Bereich der Imperativen Programmiersprachen verlässt. Denn >> bei denen würde das (im gegensatz zu Bereichen oder Masken) umfangreiche >> defizile Definition erfordern, wenn und in welcher Reihenfolge diese >> Funktionen denn aufgerufen würden. > > PHP tut das so.switch(true) > { > case $zeit===$mitternacht: tuwas(); break; > } > Hat seines Reiz! Erstens ist "PHP tut das so" ein sehr gutes Argument die Idee direkt zu verwerfen. Zweitens ist das, was du dort zeigst, nicht das, was gemeint war. Du hast keinen Funktionsaufruf im case-Wert.
Gast
#5419302
Ma W. schrieb: > Zweitens ist das, was du dort zeigst, nicht das, was gemeint war. Du > hast keinen Funktionsaufruf im case-Wert. Das ist irrelevant! Da darf alles stehen, was einen Wert liefert. Auch eine Funktion.
Gast
#5419309
Programmiersprachentheaterintendant schrieb: > Das steht in der Sprachspezifikation geschrieben, wo hoffentlich nicht > so oft wie in C et al. "behaviour is left to the implementor" vorkommt. Ich hatte jetzt gehofft, dass du wenigstens versuchst es zu definieren. > Die selben Fragen stellen sich bei If-Kaskaden. Es stellen sich viel mehr Fragen. Was machst du z.B. bei einem fall-through? Funktion aufrufen, oder nicht? > Also wozu überhaupt ein so eingeschränktes "switch"? Das geht mit Arrays > genausogut. Ja dann mach mal vor, wie das "mit Arrays genausogut" geht.
Gast
#5419312
Arduino F. schrieb: > Das ist irrelevant! Nein, ist es nicht, für diese Frage. > Da darf alles stehen, was einen Wert liefert. > Auch eine Funktion. Ok. Dann kannst du ja auch sicher die Regeln aufzählen, wann und wie Funktionen aufgerufen werden, die im case-Wert stehen.
Gast
#5419316
Ma W. schrieb: > Ok. Dann kannst du ja auch sicher die Regeln aufzählen, wann und wie > Funktionen aufgerufen werden, die im case-Wert stehen. Die Auswertungen im Case finden dann statt, wenn der Programmlauf an der Stelle ankommt. Der Nachteil ist offensichtlich: Damit wären, bezogen auf C oder C++, sämtliche Optimierungsmöglichkkeiten des Kompilers aus dem Rennen. Also nix mehr mit vorberechneten Sprungtabellen, welche ein Kompiler nur erstellen kann, wenn ihm die Case Werte VORHER bekannt sind. Immerhin erlaubt C++ mittlerweile Bereiche. > case 4 ... 16: tuwas();break;
Gast
#5419324
Arduino F. schrieb: > Die Auswertungen im Case finden dann statt, wenn der Programmlauf an der > Stelle ankommt. Und wann tut er das? Werden erst alle cases aufgelöst, um dann zu entscheiden welcher angesprungen wird? Oder werden sie in einer bestimmten Reihenfolge ausgewertet, wie if-else-if? Was passiert beim fall-through? Wird die Funktion des Cases aufgerufen? Das alles braucht ein sehr komplexes Regelwerk und ist schwer zu durchblicken und fehleranfällig, weil die Aufrufe nicht direkt offensichtlich sind. Aber das ist bei PHP ja ein Designmerkmal.
Gast
#5419339
Das ist nicht kompliziert.... Du machst es kompliziert.... Ma W. schrieb: > Werden erst alle cases aufgelöst, um dann zu entscheiden welcher > angesprungen wird? Nein. Ma W. schrieb: > Oder werden sie in einer bestimmten Reihenfolge ausgewertet, wie > if-else-if? Ja. Ma W. schrieb: > Was passiert beim fall-through? Wird die Funktion des Cases aufgerufen? Nein! Wenn keine Auswertung nötig ist, wird auch keine gemacht. Und beim "fall-through" ist keine Auswertung nötig. Ma W. schrieb: > Das alles braucht ein sehr komplexes Regelwerk und ist schwer zu > durchblicken und fehleranfällig, weil die Aufrufe nicht direkt > offensichtlich sind. Nur wenn du von deiner starren C/C++ Sicht darauf schaust. Ansonsten, ist das schon recht gut intuitiv erfassbar. Ma W. schrieb: > Aber das ist bei PHP ja ein Designmerkmal. PHP wurde dazu erfunden um Hypertexte zu manipulieren. Soll möglichst Plattformneutral arbeiten. Ist halt eine ganz andere Zielsetzung, als die Hauptanwendung von C/C++. C wurde erfunden um Betriebssystemkerne zu schreiben.
Gast
#5419357
Arduino F. schrieb: > Nur wenn du von deiner starren C/C++ Sicht darauf schaust. Ich habe keine starre C/C++ Sicht. Ich habe eine Sicht für sinnvolle und unsinnig komplexe Dinge. > Ansonsten, ist das schon recht gut intuitiv erfassbar. Ein Umsortieren der cases kann die Semantik ändern, je nachdem ob der Case-Wert Nebenwirkungen hat. Ziemlich gefährlich. Bei if-else-if ist der Codeflow offensichtlicher. >Und beim "fall-through" ist keine Auswertung nötig. Und das weiß auch jeder Programmierer und der Code unterhalb des cases nimmt nicht an, dass die Funktion aufgerufen wurde? Gefährlich. >PHP wurde dazu erfunden um Hypertexte zu manipulieren. >Soll möglichst Plattformneutral arbeiten. Und deshalb hat es total bekloppte Regeln? Macht der total unbrauchbare inline-if-operator es also plattformneutraler und besser für Hypertexte?
Gast
#5419365
Arduino F. schrieb: > PHP wurde dazu erfunden um Hypertexte zu manipulieren. > Soll möglichst Plattformneutral arbeiten. Ja, PHP ist auf jeder Plattform wüst zusammengepfuschte Sch**ße.
Gast
#5419374
http://php.net/manual/de/control-structures.switch.php Der eigentliche/häufigste Grund für die Verwendung von: > switch(true) > { > case $zeit===$mitternacht: tuwas(); break; > } Ist der typsichere Vergleich. Ma W. schrieb: > je nachdem ob der > Case-Wert Nebenwirkungen hat. > Ziemlich gefährlich. Seiteneffekte sind IMMER gefährlich! Auch an dieser Stelle. Und genauso nützlich sind sie, wenn man weiß, was man tut. Es ist immer schwer, Äpfel mit Birnen zu vergleichen, wenn persönliche Vorlieben im Spiel sind. Darum interessiert mich ein Besser oder Schlechter, in diesem Zusammenhang nicht. Ma W. schrieb: > Und deshalb hat es total bekloppte Regeln? > Macht der total unbrauchbare inline-if-operator es also > plattformneutraler und besser für Hypertexte? Bitte keine (Vor)Urteile in Fragen.... Das widerspricht allen üblichen Regeln für konstruktive Dialoge.
Gast
#5419411
Arduino F. schrieb: > Der eigentliche/häufigste Grund für die Verwendung von: >> switch(true) >> { >> case $zeit===$mitternacht: tuwas(); break; >> } > > Ist der typsichere Vergleich. Man braucht es also, um ein anderes Sprachdefizit mit einem völlig verrückten Konstrukt auszugleichen. Das passt natürlich wieder in das PHP-Bild.
Gast
#5419417
Ma W. schrieb: > Man braucht es also, um ein anderes Sprachdefizit mit einem völlig > verrückten Konstrukt auszugleichen. Und wieder ein Urteil..... Offensichtlich bist du eher auf Krawall aus. Nicht ein einem Dialog interessiert. Man kann das laxe Typehandling von PHP als Feature, oder als (design)Fehler betrachten. Das bleibt ganz dir überlassen.... Tipp: Falls du doch mal mit PHP arbeiten musst, wird dir deine engstirnige Einstellung fürchterlich im Wege rum stehen.
Gast
#5419422
Arduino F. schrieb: > Falls du doch mal mit PHP arbeiten musst Nein danke.
Gast
#5419426
> Da man bei Hochsprachen sich vom Wissen was der Compiler hinter den > Kulissen tut trennen sollte, sind mir Sprachen lieber welche sinngemäss > auch folgendes erlauben ... Der Haken ist: switch/case ist in C ein spezieller Ersatz für if/else Ketten, welcher gewährleistet, dass jeder Sprung gleich viel Zeit in Anspruch nimmt. Dies wäre mit variablen case-Werten nicht möglich. Aus dem selben Grund kann man in C auch keine Strings beim case benutzen.
Gast
#5419427
Arduino F. schrieb: > Man kann das laxe Typehandling von PHP als Feature, oder als > (design)Fehler betrachten. PHP hat kein Design. Es wurde einfach rangefrickelt, was konkret gerade gebraucht wurde, nach Aussage von Lerdorf. Zudem war PHP ursprünglich auch nicht als Sprache entworfen worden. Das Ergebnis ist dann wie zu erwarten ein Clusterfsck. Manches ist auch nicht mit dem Amateurstatus zu erklären, den Lerdorf damals hatte. Daß Funktionen mal in C-Namenskonvention bekannt sind, mal nach Java-Art, daß es mal "f(needle, haystack)" und mal "f(haystack, needle)" heißt, ist einfach Zeugnis einer durch und durch schlampigen Grundeinstellung. Und wie man eine Websprache entwickeln kann, für die es keinen Unterschied zwischen Codestrings und Datenstrings gibt, ist mir auch ein Rätsel. Gerade so, als ob die buffer overflows von C auf von-Neumann-Rechnern kein mahnendes Beispiel gewesen wären. 90% der Lücken in Wordpress & Co kommen durch diese Schlamperei zustande.
Gast
#5419433
Ich sehe das auch so. Javascript ist schon ätzend, aber PHP wirklich schlimm. Ich bin froh, dass in meiner Firma sogar die Frontend Entwickler damit begonnen haben, den PHP Code Schritt für Schritt zu reduzieren.
Gast
#5419553
Stefanus F. schrieb: > Der Haken ist: switch/case ist in C ein spezieller Ersatz für if/else > Ketten, welcher gewährleistet, dass jeder Sprung gleich viel Zeit in > Anspruch nimmt. Wo ist das definiert?
Gast
#5419622
Ma W. schrieb: > Wo ist das definiert? Gar nicht, denn der Compiler ist auch frei, ein switch als if/then/else zu implementieren. Das macht er insbesondere, wenn der umspannte Wertebereich sehr groß ist und eine Sprungtabelle daher zu groß würde. Besonders lustig ist sowas, wenn man switch/case in einem Interrupt verwendet, alles gut ist und man ein case hinzufügt - und auf einmal ein komplett anderes Timing der ISR hat. Weil es dann unversehens zu einer if/then/else-Kette wurde.
Gast
#5419632
Ob eine Zwischenspeicher-Variable lesbarer ist, würde ich anhand des Falls unterscheiden: Wenn die Funktion nur eine Zugriffsfunktion auf das zu Unterscheidende ist, gewinnt man IMO nichts:
Wen die Funktion primär irgendetwas bewirkt und zusätzlich einen Status zurückgibt, den man auswertet, würde ich es so besser finden:
Hier passieren zwei verschiedene Dinge in zwei Schritten. Den
wichtigeren Schritt würde ich hier nicht in der Klammer des switch()
verstecken.
case RUNNING: bla(); break;
case OFF: fasel(); break;
case ERROR: complain(); break;
}
[/c]
Wen die Funktion primär irgendetwas bewirkt und zusätzlich einen Status
zurückgibt, den man auswertet, würde ich es so besser finden:
Hier passieren zwei verschiedene Dinge in zwei Schritten. Das wichtigere würde ich nicht in der Klammer des switch() verstecken.
Gast
#5419635
Was ist hier passiert? So sollte es: Ob eine Zwischenspeicher-Variable lesbarer ist, würde ich anhand des Falls unterscheiden: Wenn die Funktion nur eine Zugriffsfunktion auf das zu Unterscheidende ist, gewinnt man IMO nichts:
Wen die Funktion primär irgendetwas bewirkt und zusätzlich einen Status zurückgibt, den man auswertet, würde ich es so besser finden:
Hier passieren zwei verschiedene Dinge in zwei Schritten. Den wichtigeren Schritt würde ich hier nicht in der Klammer des switch() verstecken. Tom schrieb: > > Wen die Funktion primär irgendetwas bewirkt und zusätzlich einen Status > zurückgibt, den man auswertet, würde ich es so besser finden: >
Der Nachteil an so einer Vorgehensweise ist, dass man in den umgebenden Block einen Bezeichner einführt, den man u.U. nur im Block des switch-stmt haben möchte. In C++ kann man folgendes schreiben:
oder auch
Gast
#5419713
>> Der Haken ist: switch/case ist in C ein spezieller Ersatz für if/else >> Ketten, welcher gewährleistet, dass jeder Sprung gleich viel Zeit in >> Anspruch nimmt. > Wo ist das definiert? Keine Ahnung, woher ich das habe. Es gilt jedenfalls nicht nur für den gcc, soviel ist sicher. Infos dazu: http://lazarenko.me/switch/ https://www.codeproject.com/Articles/100473/Something-You-May-Not-Know-About-the-Switch-Statem https://blogs.msdn.microsoft.com/abhinaba/2006/12/18/switches-and-jump-tables/
Gast
#5419720
Stefanus F. schrieb: > Keine Ahnung, woher ich das habe. Soso. > Es gilt jedenfalls nicht nur für den > gcc, soviel ist sicher. Überhaupt nichts ist sicher. Das ist kein garantiertes Verhalten. Auch der gcc generiert if-else-if für switch, wenn er sich dazu entscheidet. Stefanus F. schrieb: > Der Haken ist: switch/case ist in C ein spezieller Ersatz für if/else > Ketten, welcher gewährleistet, dass jeder Sprung gleich viel Zeit in > Anspruch nimmt. Nope, das ist nirgends so definiert und das wäre allein schon aufgrund der Eigenschaften der Hardware auch praktisch unmöglich zu gewährleisten. Compiler kennen diverse verschiedene Methoden, switch() Statements umzusetzen, die sie je nach Anzahl und Verteilung der Werte auswählen. Keine davon produziert jedoch auf PC-Prozessoren der letzten 20 Jahre eine wiederholbare und vom Wert unabhängige Laufzeit. Auch ein Table-Switch kann aufgrund des branch target predictors von einer Ausführung zur nächsten unterschiedlich lange dauern, und kann eine vom Wert oder der Folge von Werten abhängige Laufzeit haben. Zudem kann ein einziges geändertes oder hinzugefügtes Case-Label die verwendete Methode völlig umkrempeln.
Gast
#5419739
Wilhelm M. schrieb: > Der Nachteil an so einer Vorgehensweise ist, dass man in den umgebenden > Block einen Bezeichner einführt, den man u.U. nur im Block des > switch-stmt haben möchte. Kein Problem in C:
Gast
#5419742
Ma W. schrieb: > Programmiersprachentheaterintendant schrieb: >> Also wozu überhaupt ein so eingeschränktes "switch"? Das geht mit Arrays >> genausogut. > > Ja dann mach mal vor, wie das "mit Arrays genausogut" geht. Du hast danach gefragt, beschwere Dich anschliessend nicht:
Nop schrieb: > Wilhelm M. schrieb: > >> Der Nachteil an so einer Vorgehensweise ist, dass man in den umgebenden >> Block einen Bezeichner einführt, den man u.U. nur im Block des >> switch-stmt haben möchte. > > Kein Problem in C: > >
Nö, der Bezeichner erfolg ist nach wie vor außerhalb des switch-stmt sichtbar, etwa direkt nach der } des switch-stmt.
Gast
#5419749
Wilhelm M. schrieb: > Nö, der Bezeichner erfolg ist nach wie vor außerhalb des switch-stmt > sichtbar, etwa direkt nach der } des switch-stmt. Spielt keine Rolle, weil man deswegen den Block vor der Deklaration einführen kann. Im Übrigen geht es in diesem Thread ausweislich des Postings #3 um C, nicht C++, und es wäre nett, wenn Du aufhören würdest, C-Threads mit C++ zuzuspammen.
Gast
#5419753
Programmiersprachentheaterintendant schrieb: > Du hast danach gefragt, beschwere Dich anschliessend nicht: > functab[selector](param1, param2); Oder mit computed goto, also goto via Array-Index auf ein Array, in dem Labeladressen stehen. Das ist allerdings nicht Standard-C, sondern GCC und Clang können es. Nop schrieb: > Wilhelm M. schrieb: > >> Nö, der Bezeichner erfolg ist nach wie vor außerhalb des switch-stmt >> sichtbar, etwa direkt nach der } des switch-stmt. > > Spielt keine Rolle, weil man deswegen den Block vor der Deklaration > einführen kann. Das könnte man ja auch in C++, aber ich habe es aus gutem Grund nicht genannt, denn es löst das Problem nicht. > Im Übrigen geht es in diesem Thread ausweislich des Postings #3 um C, > nicht C++, und es wäre nett, wenn Du aufhören würdest, C-Threads mit C++ > zuzuspammen. Den Ausflug in PHP hattest Du wohl übersehen? Nicht alles, was einen Blick über den Tellerrand bietet, ist Spam.
Gast
#5419769
Nop schrieb: >> Du hast danach gefragt, beschwere Dich anschliessend nicht: >> functab[selector](param1, param2); > > Oder mit computed goto, also goto via Array-Index auf ein Array, in dem > Labeladressen stehen. Das ist allerdings nicht Standard-C, sondern GCC > und Clang können es. Man könnte auch inline-assembly nehmen.
Gast
#5419771
Ma W. schrieb: > Man könnte auch inline-assembly nehmen. Das wäre dann aber nicht mehr portabel. Computed goto funktioniert auf ARM genauso wie auf x86, wenn der Compiler es unterstützt. Da man bekanntlich nicht verfrüht optimieren soll, hat man zunächst einmal ja ohnehin eine Codeversion, die ohne solche Scherze auskommt. Sofern es was bringt, kann man dann die Version mit computed goto hinzufügen - und die andere per ifdef drinlassen, falls man das mal mit einem Compiler durchziehen will, der das nicht unterstützt. Nop schrieb: > Ma W. schrieb: > >> Man könnte auch inline-assembly nehmen. > > Das wäre dann aber nicht mehr portabel. Computed goto funktioniert auf > ARM genauso wie auf x86, wenn der Compiler es unterstützt. > > Da man bekanntlich nicht verfrüht optimieren soll, hat man zunächst > einmal ja ohnehin eine Codeversion, die ohne solche Scherze auskommt. > Sofern es was bringt, kann man dann die Version mit computed goto > hinzufügen - und die andere per ifdef drinlassen, falls man das mal mit > einem Compiler durchziehen will, der das nicht unterstützt. Jo, genau. Das kannst Du per ifdef doch auch protabel machen. Oh man ... Aus dem Konstrukt switch / if das beste heraus zu holen, ist Sache des Compiler.
Gast
#5419785
Wilhelm M. schrieb: > Aus dem Konstrukt switch / if das beste heraus zu holen, ist Sache des > Compiler. Schafft er aber halt nicht immer. Falls man es auf Geschwindigkeit anlegt, wird's halt mitunter etwas dreckig. Ob es das wert ist, muß der Entwickler anhand des vorher/nachher-Profilings entscheiden. Wilhelm M. schrieb: > Aus dem Konstrukt switch / if das beste heraus zu holen, ist Sache des > Compiler. Von Hand per if/else einen balancierten binary tree search zu implementieren ist äusserst spassbefreit, ganz besonders wenn sich gelegentlich was dran ändert. Und das ist jene Variante, die bei einer grösseren Anzahl von Werten und arg löchriger Werteverteilung oft die effektivste sein wird. Da habe ich etwas los getrete, wovon ich nur wenig nachvollziehen kann. Daher vielleicht ein konkretes Bsp das nicht korrekt (vollkommen unkontrolliert) läuft; Es handelt sich um 2 Selbsthaltungen, die erst nach bestimmten Startbedingungen/-routinen ablaufen sollen. Daher der default-Block.
Mir ist bewusst, dass der eine oder Andere diese switch-Schreibweise "unsauber" findet. Aber wo steckt der konkrete Fehler?
Gast
#5422952
__Son´s B. schrieb: > Daher vielleicht ein konkretes Bsp das nicht korrekt (vollkommen > unkontrolliert) läuft; Zu einer Fehlerfrage gehört: 1) Welches Verhalten wurde bei welchen Eingabedaten erwartet? 2) Welches Verhalten wurde stattdessen bei welchen Eingabedaten beobachtet? __Son´s B. schrieb: > Aber wo steckt der konkrete Fehler? Ein konkreter Fehler ist da nicht zu sehen, nur potentielle Fehler. Was geschieht, wenn die Funktionen "Entprell_XX" andere Werte als 1 oder 2 zurückliefern? Welchen Wert haben die Variablen PB1_high/PB2_high? Warum rufst Du die Macros "LED_HELL_ON" etc. nicht direkt in Deinen beiden switch-Statements auf, und verwendest die zusätzlichen Variablen PB1_high etc.? Werden die noch irgendwo anders verwendet? Warum die unnötige Indirektion? Besser:
Rufus Τ. F. schrieb: > Ein konkreter Fehler ist da nicht zu sehen, nur potentielle Fehler. > Was geschieht, wenn die Funktionen "Entprell_XX" andere Werte als 1 oder > 2 zurückliefern? Welchen Wert haben die Variablen PB1_high/PB2_high? Entprell_XX liefert bei Flankenanstieg einen "1"-Impuls, bei Flankenabfall einen "2"-Impuls. Sonst "0", hier soll der letzte Zustand erhalten bleiben: ON oder OFF. Daher weise PB1_high bei Flankenanstieg "1" und bei Flankenabfall eine "2" zu. Dies scheint mir die einfachste und flexibelste Lösung zu sein... Rufus Τ. F. schrieb: > Warum rufst Du die Macros "LED_HELL_ON" etc. nicht direkt in Deinen > beiden switch-Statements auf, und verwendest die zusätzlichen Variablen > PB1_high etc.? Werden die noch irgendwo anders verwendet? Ich wollte eine universelle Taster-Überwachung schaffen, die immer und überall (in späteren c-Prog) einsetzbar sind. In deisem konkreten Prog wird die Var XXX_high nicht weiter verwendet. Nop schrieb: > Zu einer Fehlerfrage gehört: > 1) Welches Verhalten wurde bei welchen Eingabedaten erwartet? > 2) Welches Verhalten wurde stattdessen bei welchen Eingabedaten > beobachtet? Rufus Τ. F. schrieb: > Ein konkreter Fehler ist da nicht zu sehen, nur potentielle Fehler. FEHLER GEFUNDEN! Es war ein Hardwarefehler auf der Versuchs-LP. Daher noch einmal DANKE für eure Anmerkungen!
Gast
#5423013
Mir ist (nach deinen Bezeichnern zu urteilen) nicht klar, warum LED_HELL
nur an sein darf, wenn auch LED_DUNKEL an ist.
Wenn Entprell_PBx zylisch aufgerufen werden muss (also mit jedem Aufruf
getaktet ist), dann ist es m.E. nicht glücklich, dies im darauf
reagierenden Code zu verteilen. Je nach Architektur ist meist ein
lokaler (oder globaler) Tastatentatus sinnvoller, also z.B.
KeyPB1={An=1/Make=3/Break=2/Aus=0} oder entsprechende boolsche
Tastaturabbilder (je 0/1): (Key.PB1, Key.PB2, ..., KeyMake.PB1, .... ,
KeyBreak.PB1, ...}
Wenn Entprell notfalls auch mehrfach oder garnicht aufgerufen werden
kann, ... dann ist es nicht die Entprellung sondern fragt den Zustand
der Tasten ab. Das sollte dann entsprechend billig sein, dass ggf. auch
direkter code mit mehrfachen ifs möglich ist.
Achim S. schrieb: > Mir ist (nach deinen Bezeichnern zu urteilen) nicht klar, warum LED_HELL > nur an sein darf, wenn auch LED_DUNKEL an ist. Beide Tasten und somit deren Ausgänge, sind vollkommen unabhängig voneiander. Ich möchte einen Tastenabfrage-Block, Tasten/Schalterabfrage 1-4, die in ihre Var XXX_high schreiben. Im Anschluss kommt erst ein Handlungsblock bei dem ich die Var XXX_high auswerte. Mein oben aufgeführter Code ist ein Versuchsblock um zu sehen, was nach Tastenentpr. und Selbshaltung raus kommt.
Gast
#5423065
Wer mal im Team an Großprojekten programmieren möchte sollte sich einen brauchbaren Programmierstil angewöhnen. Derartiges Zeugs (switch(fun()) ... gehört nicht dazu. Jeden Abend läuft Axivion über den Sourcecode und liefert Warnungen und Verstöße gegen die coding guide lines. Das kommt nicht gut bei der Führung an wenn bestimmte Mitarbeiter immer wieder durch solche Bullshit auffallen. Zudem wollen >50 andere Entwickler auch die ein oder andere Klasse verbauen und da spielt Lesbarkeit eine Rolle. Das ist ja verrückt; wird zuerst PB2 und danach PB1 abgefragt, funktioniert PB1/Dunkel einwandfrei, aber keine Reaktion wenn PB2/Hell betätigt wird.
Werden die beiden Blöcke umgetauscht, zuerst PB1-Abfrage+Auswertung und danach PB2, funktionieren beide Blöcke einwandfrei!
Wo ist denn hier die Logik? NichtWichtig schrieb: > Wer mal im Team an Großprojekten programmieren möchte sollte sich einen > brauchbaren Programmierstil angewöhnen. > > Derartiges Zeugs (switch(fun()) ... gehört nicht dazu. Kannst Du das auch begründen? > > Jeden Abend läuft Axivion über den Sourcecode und liefert Warnungen und > Verstöße gegen die coding guide lines. Das ist kein Grund bzw. vielmehr ein Grund ggf. das Regelwerk des Tools anzupassen. Wilhelm M. schrieb: > Kannst Du das auch begründen? Muss man das? Man legt halt in einem Team einmal die Regeln fest. Dann sollte man sich daran halten - der Einheitlichkeit des Codes wegen. > Das ist kein Grund bzw. vielmehr ein Grund ggf. das Regelwerk des Tools > anzupassen. Wenn es eine Mehrheitsentscheidung gibt, ja. Aber wegen des Geschmacks eines einzelnen: nein. Frank M. schrieb: > Wilhelm M. schrieb: >> Kannst Du das auch begründen? > > Muss man das? Man legt halt in einem Team einmal die Regeln fest. Dann > sollte man sich daran halten - der Einheitlichkeit des Codes wegen. Ja, entweder gibt es objektive technische Gründe, oder es ist eben nur eine Teamfestlegung für den Geschmack, die hier natürlich keine Relevanz hat. >> Das ist kein Grund bzw. vielmehr ein Grund ggf. das Regelwerk des Tools >> anzupassen. > > Wenn es eine Mehrheitsentscheidung gibt, ja. Aber wegen des Geschmacks > eines einzelnen: nein. Genau! Mit scheint es eine Frage des Geschmacks zu sein. Und Geschmack kann man / muss man nicht begründen. Dann sollte man aber seinen eigenen oder den Geschmack ds Teams nicht anderen aufdrücken wollen.
Gast
#5423118
Wartbarkeit des codes debuggen Verständnis derer die den code benutzen aber nicht geschrieben haben. Forderungen durch Normen Wir können und wollen es uns nicht leisten miesen code weltweit bei Kunden einzusetzen. keep it simple! Was bei diesen tollen Optimierungsversuchen passiert käönnt ihr dort Autor: __Son´s Bersi__ (bersison) Datum: 15.05.2018 12:29 nachlesen hihi
Gast
#5423120
__Son´s B. schrieb: > aber keine Reaktion wenn PB2/Hell betätigt wird. > Wo ist denn hier die Logik? Achim S. schrieb: > nicht klar, warum LED_HELL nur an sein darf, wenn auch LED_DUNKEL an ist. Nochmal: Du machst zweimal alle LEDs aus, mit "else LED_ALLE_OFF;" Wenn es funktioniren soll, solltest Du im else-Zweig nur die eine LED ausmachen. Oder am Anfang alle aus und dann nur setzen (spielt bei LEDs meist keine Rolle). Wenn es noch weitere Fehler gibt, werden die wohl in den Entprell-Routinen zu suchen sein. Poste deren Code ruhig mit. NichtWichtig schrieb: > Wartbarkeit des codes Wo liegt bei
die Nichtwartbarkeit? Was wäre denn D.E. warum besser? > debuggen s.o. Was wäre denn D.E. warum besser? > Verständnis derer die den code benutzen aber nicht geschrieben haben. s.o. Was wäre denn D.E. warum besser? > Forderungen durch Normen Das gilt für Euch, aber nicht allgemein. > keep it simple! Wie wäre es denn einfacher? Achim S. schrieb: >Wenn es funktioniren soll, solltest Du im else-Zweig nur die eine LED >ausmachen. Oder am Anfang alle aus und dann nur setzen (spielt bei LEDs > meist keine Rolle). Tatsächlich war das der Fehler! Trotzdem verstehe ich nicht, warum beim Reihenfolgewechsel, erst PB1 danach PB2, die Funktion iO war? Habs mehrfach ausprobiert - Zufall? Wilhelm M. schrieb: > Dann sollte man aber seinen eigenen oder den Geschmack ds Teams nicht > anderen aufdrücken wollen. Darauf wollte ich hinaus. Unter Geschmack zähle ich übrigens nicht nur die Wahl des Coding-Styles, sondern auch die individuelle Wahl der Programmiersprache. Das sollte man durchaus auch mal respektieren und sich die Gebetsmühle "In C++ geht das alles viel schöner als in C" ab und zu verkneifen. ;-) Wilhelm M. schrieb: > Wo liegt bei switch(foo()) { > ... > } > > die Nichtwartbarkeit? 1. Man kann sich u.U. den Rückgabewert von foo() nicht per printf() testweise ausgeben lassen. Bei
ist das einfach:
2. Wird später mal die Semantik in foo() geändert, so dass zum Beispiel für einen ganzen Zahlenbereich der switch() gar nicht durchgeführt werden soll, muss man mühsam den Funktionsaufruf und den switch() wieder auseinanderpopeln. Beispiel: Es wird später eine Fehlerbehandlung in foo() eingebaut. Fehler sollen als negative Return-Werte zurückgegeben werden und zu einem Abbruch der Verarbeitung führen. Bei
ist das einfach:
3. Breakpoint im Debugger hinter den Aufruf von foo() setzen ist beinahe unmöglich. Dein Argument, dass Du keinen Debugger nutzt, ist kein Argument. Es gibt durchaus Gründe, einen Debugger für bestimmte Szenarien zu nutzen statt ein spezielles Test-Case dafür zu verwenden. Am wenigsten geeignet sind übrigens Test-Cases, die von demselben Programmierer stammen, der auch den zu testenden Code geschrieben hat. Solche Test-Cases berücksichtigen dann nur das, was man auch schon im Code verzapft hat. Daher sind sie im allgemeinen ungeeignet. Ein Debugger jedoch kann da schon mal für den einen oder anderen Überraschungseffekt sorgen: "Stimmt, soooo habe ich das gar nicht bedacht!" Frank M. schrieb: > Wilhelm M. schrieb: >> Wo liegt bei switch(foo()) { >> ... >> } >> >> die Nichtwartbarkeit? > > 1. Man kann sich u.U. den Rückgabewert von foo() nicht per printf() > testweise ausgeben lassen. Ich kann z.B. im gdb einen bedingten BP setzen im switch(): foo()==42 > 2. Wird später mal die Semantik in foo() geändert, so dass zum Beispiel > für einen ganzen Zahlenbereich der switch() gar nicht durchgeführt > werden soll, muss man mühsam den Funktionsaufruf und den switch() wieder > auseinanderpopeln. > > Beispiel: Es wird später eine Fehlerbehandlung in foo() eingebaut. > Fehler sollen als negative Return-Werte zurückgegeben werden und zu > einem Abbruch der Verarbeitung führen. > > Bei >
> > ist das einfach: > >
Das kann ich doch alles im switch erledigen. Wozu das if-stmt? Das ist für meinen Geschmack (s.o.) nun wieder das Gegenteil von KISS und Lokalität. > 3. Breakpoint im Debugger hinter den Aufruf von foo() setzen ist beinahe > unmöglich. In der von mir genannten Art erzwingt die Schreibweise, dass der gesamte Wertebereich von foo() im switch abgedeckt ist / sein sollte. Dann kann ich in jedes case/default ein BP setzen. Und wie gesagt: würde man hier nur dieses eine, kleine, neue feature von C++ nutzen (s.u.), nämlich in if-stmts und switch-stmts auch init-stmts einbauen zu können, so hätte man sehr viel gewonnen: hier genau Einfachheit und Lokalität. > Dein Argument, dass Du keinen Debugger nutzt, ist kein Argument. Das wollte ich nicht damit behaupten. Allerdings ist es extrem selten geworden ;-) C++ und strong-types lassen grüßen. > Es gibt > durchaus Gründe, einen Debugger für bestimmte Szenarien zu nutzen statt > ein spezielles Test-Case dafür zu verwenden. > > Am wenigsten geeignet sind übrigens Test-Cases, die von demselben > Programmierer stammen, der auch den zu testenden Code geschrieben hat. > Solche Test-Cases berücksichtigen dann nur das, was man auch schon im > Code verzapft hat. Daher sind sie im allgemeinen ungeeignet. Das brauchst Du mir nicht zu erklären. Im übrigen habe ich das auch nicht gesagt. > Ein Debugger jedoch kann da schon mal für den einen oder anderen > Überraschungseffekt sorgen: "Stimmt, soooo habe ich das gar nicht > bedacht!" Wie schon des öfteren gesagt: statt ein Laufzeit-Debugging durchzuführen, sollte man seine Energie darauf verwenden, Code so zu gestalten, dass er nur schwer falsch und leicht richtig benutzt werden kann. Und gerade in dieser Hinsicht hat C nun so seine Schwächen und C++ seine Stärken. Zudem sehe ich bei sehr vielen C-Problemen, die hier immer und immer wieder besprochen werden, dass man sie in C++ nicht hätte. Und dass man die meisten dieser Programme einfach als C++ Code übersetzen könnte und dabei schrittweise die besseren Möglichkeiten dieser Sprache nutzen könnte. Deswegen weise ich darauf hin. Wilhelm M. schrieb: > Dann sollte man aber seinen eigenen oder den Geschmack ds Teams nicht > anderen aufdrücken wollen. Passt nicht zur Gebetsmühle: Wilhelm M. schrieb: > Und gerade in dieser Hinsicht hat C nun so seine Schwächen und C++ seine > Stärken. Zudem sehe ich bei sehr vielen C-Problemen, die hier immer und > immer wieder besprochen werden, dass man sie in C++ nicht hätte. Und > dass man die meisten dieser Programme einfach als C++ Code übersetzen > könnte und dabei schrittweise die besseren Möglichkeiten dieser Sprache > nutzen könnte. Deswegen weise ich darauf hin. Wilhelm M. schrieb: > Ich kann z.B. im gdb einen bedingten BP setzen im switch(): foo()==42 Im gdb mag das ja gehen. Es gibt aber durchaus noch andere Debugger, welche zeilenoriientiert arbeiten und es nicht hinbekommen, den return-Wert von foo() anzuzeigen, wenn dieses innerhalb von switch() steht. > Das kann ich doch alles im switch erledigen. Wozu das if-stmt? Das ist > für meinen Geschmack (s.o.) nun wieder das Gegenteil von KISS und > Lokalität. Ich kann und will das nicht im switch erledigen, denn: foo() wird noch an 100 anderen Orten aufgerufen. Soll ich dann die Fehlerbehandlung an 100 Stellen machen? Wenn es 200 verschiedene negative Return-Werte gibt, soll ich die dann alle einzeln in genau diesem Switch (und an hundert anderen Orten) abfackeln? Und komm mir bitte nicht mit gcc-Erweiterungen, dass man hier ganze Zahlenbereiche im switch angeben kann. Das ist kein Standard. Ein vorzeitiges:
ist genau die Lösung für das geschilderte Szenario. Gerade dann, wenn der 201te negative Wert später hinzukommt. Dann brauche ich nämlich an dieser Stelle gar nichts zu ändern! > In der von mir genannten Art erzwingt die Schreibweise, dass der gesamte > Wertebereich von foo() im switch abgedeckt ist / sein sollte. Das ist nur sinnvoll, wenn Du foo() nur an dieser einen Stelle im Programm aufrufst, siehe oben. Das ist aber praxisfremd. Im Allgemeinen nutzt man Funktionen, damit man wiederkehrenden Code nur einmal schreiben und mehrfach von verschiedenen Stellen aus aufrufen kann. Frank M. schrieb: > Wilhelm M. schrieb: > >> Ich kann z.B. im gdb einen bedingten BP setzen im switch(): foo()==42 > > Im gdb mag das ja gehen. Es gibt aber durchaus noch andere Debugger, > welche zeilenoriientiert arbeiten und es nicht hinbekommen, den > return-Wert von foo() anzuzeigen, wenn dieses innerhalb von switch() > steht. Ja, die gibt es leider. Und das ist der Grund, warum auch hier eben C++ besser ist:
Auch wenn Du es nicht magst, werde ich mir die Freiheit nehmen, darauf immer wieder hinzuweisen. >> Das kann ich doch alles im switch erledigen. Wozu das if-stmt? Das ist >> für meinen Geschmack (s.o.) nun wieder das Gegenteil von KISS und >> Lokalität. > > Ich kann und will das nicht im switch erledigen: die bessere Lösung steht oben > foo() wird noch an 100 anderen Orten aufgerufen. Soll ich dann die > Fehlerbehandlung an 100 Stellen machen? Genau das wirst Du wohl machen müssen: die Fehlerbehandlung s.o. > Wenn es 200 verschiedene > negative Return-Werte gibt, soll ich die dann alle einzeln in genau > diesem Switch (und an hundert anderen Orten) abfackeln? Dazu hast Du hoffentlich eine eigene Funktion oder generischen Mechanismus, um Replication zu vermeiden ... alles andere wäre auch praxisfern. > Und komm mir > bitte nicht mit gcc-Erweiterungen, dass man hier ganze Zahlenbereiche im > switch angeben kann. Das ist kein Standard. Schon mal was von falltrough gehört? Naja, ist auch mal wider Standard-C++, sorry. > Ein vorzeitiges: >
> > ist genau die Lösung für das geschilderte Szenario. Gerade dann, wenn > der 201te negative Wert später hinzukommt. Dann brauche ich nämlich an > dieser Stelle gar nichts zu ändern! Wenn Du es richtig machst, brauchst Du im switch auch nichts zu ändern. Und Du weißt sicher, dass man das so in C++ auch nicht machen müsste / würde (und die Lösung heisst jetzt nicht exception).
Gast
#5423511
Wilhelm M. schrieb: > Und das ist der Grund, warum auch hier eben C++ besser ist: Irrelevant. Frank M. schrieb: > Bei >
> > ist das einfach: > >
Und Du empfiehlst wahrscheinlich auch
zu schreiben statt
nehme nun ich an. Nop schrieb: > Wilhelm M. schrieb: > >> Und das ist der Grund, warum auch hier eben C++ besser ist: > > Irrelevant. Der nächste C-Standard soll C2x (etwa 2022) sein. Und ich denke, dass viel von den "kleinen C++-Features" (s.o.) bis C++20 auch dort einfließen wird. Das ist natürlich noch lange hin und schade für die, die nicht willens sind, über den Tellerrand hinaus zu blicken. Wilhelm M. schrieb: > Nop schrieb: >> Wilhelm M. schrieb: >> >>> Und das ist der Grund, warum auch hier eben C++ besser ist: >> >> Irrelevant. > > Der nächste C-Standard soll C2x (etwa 2022) sein. Und ich denke, dass > viel von den "kleinen C++-Features" (s.o.) bis C++20 auch dort > einfließen wird. Das ist natürlich noch lange hin und schade für die, > die nicht willens sind, über den Tellerrand hinaus zu blicken. Verschwende einfach nicht deine Zeit mit denen im Suppenteller. Es gibt eine Vielzahl von Nicks, bei denen man einfach sein Antwortbedürfnis unterdrücken muß. Aber immer klappt das nicht, wie ich selber zugeben muß ;-) Carl D. schrieb: > > Verschwende einfach nicht deine Zeit mit denen im Suppenteller. > Es gibt eine Vielzahl von Nicks, bei denen man einfach sein > Antwortbedürfnis unterdrücken muß. Ja, das ist wohl einerseits richtig. Andererseits gibt ja auch hier noch den TO und auch weitere stille Mitleser, die einfach auch mal etwas Neues erfahren wollen, statt ständig nur zu hören: das geht nur so, basta! Wilhelm M. schrieb: > Carl D. schrieb: > >> >> Verschwende einfach nicht deine Zeit mit denen im Suppenteller. >> Es gibt eine Vielzahl von Nicks, bei denen man einfach sein >> Antwortbedürfnis unterdrücken muß. > > Ja, das ist wohl einerseits richtig. Andererseits gibt ja auch hier noch > den TO und auch weitere stille Mitleser, die einfach auch mal etwas > Neues erfahren wollen, statt ständig nur zu hören: das geht nur so, > basta! Deshalb: >> Aber immer klappt das nicht, wie ich selber zugeben muß ;-)
Gast
#5423561
Wilhelm M. schrieb: > Das ist natürlich noch lange hin und schade für die, > die nicht willens sind, über den Tellerrand hinaus zu blicken. C++ hat schon vor langer Zeit aufgehört, nützlich zu sein, so what.
Gast
#5423570
Nop schrieb: > C++ hat schon vor langer Zeit aufgehört, nützlich zu sein, so what. Viele Werkzeuge sind nutzlos, in den Händen von Leuten, die damit nicht umgehen können oder wollen. Auch ist z.B. ein Spaten nicht unbedingt hilfreich, beim Teppichboden verlegen, selbst wenn man sich mit Spaten gut auskennt.
Gast
#5423627
Arduino F. schrieb: > Viele Werkzeuge sind nutzlos, in den Händen von Leuten, die damit nicht > umgehen können oder wollen. Das stimmt. Und ich freue mich ja auch über jedes Beispiel, wo irgendwas eleganter wird. Aber wieso wird hier wieder C++ als ultimativ hingestellt, ohne einen nachvollziehbaren Mehrwert zu zeigen. Was an Wilhelm M. schrieb: > Ja, die gibt es leider. > Und das ist der Grund, warum auch hier eben C++ besser ist: > if (auto result = foo(); result < 0) { > handl_error(result); > } soviel besser sein soll als
Auch in C kann ich if-Klammern überfrachten. Ist es "auto"? Ist es der Scope von result? Die Deklarationszeile? Ja, C++ wird schneller verändert, hat mehr Freiheiten, erlaubt filigranere Verbiegungen, ... aber das hier tangiert die Eigenschaften der Unterschiede nicht wirklich.
Gast
#5423638
Wer bei
ein Problem sieht, hat die Kontrolle über sein Leben verloren. Achim S. schrieb: > Arduino F. schrieb: >> Viele Werkzeuge sind nutzlos, in den Händen von Leuten, die damit nicht >> umgehen können oder wollen. > > Das stimmt. Und ich freue mich ja auch über jedes Beispiel, wo irgendwas > eleganter wird. Aber wieso wird hier wieder C++ als ultimativ > hingestellt, ohne einen nachvollziehbaren Mehrwert zu zeigen. Wie Du unten selbst zitierst, habe ich geschrieben, dass es besser geht, aber nicht als die nicht mehr zu verbessernde Lösung. > Was an > > Wilhelm M. schrieb: >> Ja, die gibt es leider. >> Und das ist der Grund, warum auch hier eben C++ besser ist: >> if (auto result = foo(); result < 0) { >> handl_error(result); >> } > > soviel besser sein soll als >
Der entscheidende, wenn auch bei diesem kleinen Beispiel eben zunächst klein ausfallende Unterschied ist die effektive Begrenzung des Gültigkeitsbereichs auf den Scope des if-stmts. Und das ist schon mal ein großer Vorteil, verhindert es doch effektiv das so oft vorkommende Recycling von Variablen aus Faulheit. Debuggen kann man es dann auch (s.o.), falls man einen schwachen Debugger hat. > Auch in C kann ich if-Klammern überfrachten. Ist es "auto"? Das "auto" kommt natürlich erst in generischem Code zum Tragen. > Ist es der > Scope von result? Die Deklarationszeile? s.o. Achim S. schrieb: > Arduino F. schrieb: >> Viele Werkzeuge sind nutzlos, in den Händen von Leuten, die damit nicht >> umgehen können oder wollen. > > Das stimmt. Und ich freue mich ja auch über jedes Beispiel, wo irgendwas > eleganter wird. Aber wieso wird hier wieder C++ als ultimativ > hingestellt, ohne einen nachvollziehbaren Mehrwert zu zeigen. Was an > > Wilhelm M. schrieb: >> Ja, die gibt es leider. >> Und das ist der Grund, warum auch hier eben C++ besser ist: >> if (auto result = foo(); result < 0) { >> handl_error(result); >> } > > soviel besser sein soll als >
. > Auch in C kann ich if-Klammern überfrachten. Ist es "auto"? Ist es der > Scope von result? Die Deklarationszeile? Ja, C++ wird schneller > verändert, hat mehr Freiheiten, erlaubt filigranere Verbiegungen, ... > aber das hier tangiert die Eigenschaften der Unterschiede nicht > wirklich. Wenn result kein int ist, sondern etwas, das man wieder abräumen muß, dann lernt man "scope" schätzen. Und natürlich das bisschen mehr gegenüber C, weil der Compiler aufräumt. auto übernimmt den Typ vom Ergebnis von foo(). Wenn man z.B. Raketen-Flugbahnen mal in INT und mal in double berechnet. Da kann auto die Lebensdauer des Fluggeräts deutlich erhöhen. Man braucht das natürlich nicht, so wie man keinen Akkuschrauber braucht und keine CNC-Bearbeitungsstation. Letzteres ist auch nicht so einfach zu bedienen, wie eine Feile und viel teuerer, wird aber trotzdem gekauft. Nop schrieb: >> Man könnte auch inline-assembly nehmen. > > Das wäre dann aber nicht mehr portabel. Computed goto funktioniert auf > ARM genauso wie auf x86, wenn der Compiler es unterstützt. Ich weise mal leise darauf hin, dass computed goto auf AVR nicht unterstützt wird.
Gast
#5423648
S. R. schrieb: > Ich weise mal leise darauf hin, dass computed goto auf AVR nicht > unterstützt wird. Interessant - wegen Harvard? S. R. schrieb: > Nop schrieb: >>> Man könnte auch inline-assembly nehmen. >> >> Das wäre dann aber nicht mehr portabel. Computed goto funktioniert auf >> ARM genauso wie auf x86, wenn der Compiler es unterstützt. > > Ich weise mal leise darauf hin, dass computed goto auf AVR nicht > unterstützt wird. Komisch, benutze ich bei einer C++ Protothreads Implementierung mit g++ auf AVR. Vielleicht weil ich mir den Compiler immer aus aktuellen Sourcen selbst baue und nicht einen WinAvr2010 benutze? Edit: gerade gelesen: AVR-GCC kann keine Offsets zweier Labeladressn berechnen. Brauchte ich aber nicht. Carl D. schrieb: > S. R. schrieb: >> Nop schrieb: >>>> Man könnte auch inline-assembly nehmen. >>> >>> Das wäre dann aber nicht mehr portabel. Computed goto funktioniert auf >>> ARM genauso wie auf x86, wenn der Compiler es unterstützt. >> >> Ich weise mal leise darauf hin, dass computed goto auf AVR nicht >> unterstützt wird. > > Komisch, benutze ich bei einer C++ Protothreads Implementierung mit g++ > auf AVR. > Vielleicht weil ich mir den Compiler immer aus aktuellen Sourcen selbst > baue und nicht einen WinAvr2010 benutze? Nein, denke genaues Lesen ist angesagt: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
Gast
#5423660
> Gültigkeitsbereichs auf den Scope des if-stmts. Und das ist schon mal > ein großer Vorteil, verhindert es doch effektiv das so oft vorkommende > Recycling von Variablen aus Faulheit. Debuggen kann man es dann auch > (s.o.), falls man einen schwachen Debugger hat. Carl D. schrieb: > Wenn result kein int ist Das meine ich. Ich brauche unbedingt C++ (mit seinem ungleich größeren Sprachumfang), um für ein mögliches Debug-Szenario mit einem beschränkten Debugger den Scope einer general-Purpose int-Variable zu begrenzen. Das ist absurd! Ja, in anderen Beispielen ist der Scope interessant und Destruktoren oder auto. Aber nicht hier! Es geht um switch, und da ist int immer richtig und gut! Egal was foo() zurückliefert. Wilhelm M. schrieb: > Nein, denke genaues Lesen ist angesagt: > > https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html Differenzen zwischen Label-Adressen gehen nicht, aber die braucht man weder für Protithreads, nicht für "Label-Arrays". Auf alle Fälle ist "geht nicht" eine starke Verbiegung der Wahrheit. Achim S. schrieb: >> Gültigkeitsbereichs auf den Scope des if-stmts. Und das ist schon mal >> ein großer Vorteil, verhindert es doch effektiv das so oft vorkommende >> Recycling von Variablen aus Faulheit. Debuggen kann man es dann auch >> (s.o.), falls man einen schwachen Debugger hat. > > Carl D. schrieb: >> Wenn result kein int ist > > Das meine ich. Ich brauche unbedingt C++ (mit seinem ungleich größeren > Sprachumfang), um für ein mögliches Debug-Szenario mit einem > beschränkten Debugger den Scope einer general-Purpose int-Variable zu > begrenzen. Das ist absurd! Genau! Ich brauche C++, weil es C nicht kann! Das C das nicht kann ist absurd. Was ist eine general-purpose int-Variable? Eine, die Du immer wieder recyclest? > Ja, in anderen Beispielen ist der Scope interessant und Destruktoren > oder auto. Aber nicht hier! Es geht um switch, und da ist int immer > richtig und gut! Ja, die alte Strategie: alles ist ein int oder ein C-String ... back to the 70s > Egal was foo() zurückliefert. Du willst also echt jeden Typ, den foo() liefert, auf ein int implizit wandeln. Oh, das nenne ich mal krass! Carl D. schrieb: > Wilhelm M. schrieb: >> Nein, denke genaues Lesen ist angesagt: >> >> https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html > > Differenzen zwischen Label-Adressen gehen nicht, aber die braucht man > weder für Protithreads, nicht für "Label-Arrays". > Auf alle Fälle ist "geht nicht" eine starke Verbiegung der Wahrheit. Was ich damit sagen wollte: da hat wohl einer eben nicht so richtig gelesen ...
Beitrag #5423672 wurde von einem Moderator gelöscht.
Gast
#5423686
Wilhelm M. schrieb: > Du willst also echt jeden Typ, den foo() liefert, auf ein int implizit > wandeln. Oh, das nenne ich mal krass! Ich vermute, Du hast Dich ein bisschen verrannt oder meinen Beitrag nur überflogen. Ich möchte gar nichts, switch macht.
Gast
#5423699
Carl D. schrieb: > Wenn man z.B. > Raketen-Flugbahnen mal in INT und mal in double berechnet. Das ist dann ein Designbug, der geradezu nach Fehlern schreit. Genauso, wenn man den Datentyp beibehält, aber mal in m/s und mal in Knoten rechnet. Grund: "principle of the least surprise" verletzt. Richtig macht man das so, daß man in einem einzigen Datenformat und einer einzigen Einheit rechnet, und zwar konsistent und überall. Bei Bedarf kann bei der Ausgabe in andere Datentypen oder Einheiten konvertiert werden. Achim S. schrieb: > Wilhelm M. schrieb: >> Du willst also echt jeden Typ, den foo() liefert, auf ein int implizit >> wandeln. Oh, das nenne ich mal krass! > > Ich vermute, Du hast Dich ein bisschen verrannt oder meinen Beitrag nur > überflogen. Ich möchte gar nichts, switch macht. Ich habe schon genau genau gelesen: Du möchtest gerne
was aber selbst in C nicht geht. Nop schrieb: > Carl D. schrieb: >> Wenn man z.B. >> Raketen-Flugbahnen mal in INT und mal in double berechnet. > > Richtig macht man das so, daß man in einem einzigen Datenformat und > einer einzigen Einheit rechnet, und zwar konsistent und überall. Und wie stellst Du das sicher, wenn alles ein double ist? Richtig ist, sich ein Typ-System zu schaffen, bei dem richtig gerechnet wird, also etwa:
"Unsinnige" Operationen werden nicht realisiert. Dann kann fast nichts mehr schief gehen.
Gast
#5423709
Ach ja, und ein switch ist für diskrete Zustände gedacht. Das für eine eigentlich kontinuierliche Größe wie eine Geschwindigkeit zu verwenden, wäre an sich schon ein Bug. Range-Checks macht man nicht mit Switch. Nop schrieb: > Ach ja, und ein switch ist für diskrete Zustände gedacht. Das für eine > eigentlich kontinuierliche Größe wie eine Geschwindigkeit zu verwenden, > wäre an sich schon ein Bug. Range-Checks macht man nicht mit Switch. Lies nochmal genau: er bezogt sich auf mein Beispiel mit dem if-stmt.
Gast
#5423719
Wilhelm M. schrieb: > Und wie stellst Du das sicher, wenn alles ein double ist? Die Magie des SI-Systems gewährleistet das schon von selber. Sicher kann man auch aus Versehen Zeit durch Weg teilen, wenn man Geschwindigkeit will, aber erstens ist das kein relevantes Szenario, und zweitens fällt sowas im Test mit Sicherheit auf - wenn nicht, hat man noch ganz andere Probleme. > Richtig ist, sich ein Typ-System zu schaffen Ja, Leute mit starkem Hang zu DSLs würden das tun. Es löst allerdings kein relevantes Problem, denn z.B. der Verlustder Mars-Sonde wäre schon verhindert worden, wenn alle überall mit demselben System gerechnet hätten.
Gast
#5423729
Wilhelm M. schrieb: > Lies nochmal genau: er bezogt sich auf mein Beispiel mit dem if-stmt. Da wäre das aus einem noch ganz anderen Grund ein Bug gewesen: negative physikalische Werte als Fehler zu interpretieren wird in dem Moment zur Überraschung, wo aus irgendwelchen Gründen das System auf einmal einen Rückwärtsgang bekommt. Siehe das Beispiel der F-16, die auf der Südhalbkugel einfach mal in Rückenlage gedreht hat wegen negativer Breitengrade. Bzw. hätte, das wurde ja im Simulator noch rechtzeitig gefunden. Richtig macht man das so, daß man erstmal die Eingabewerte auf gültige Bereiche validiert und dann einfach rechnen kann. Nop schrieb: > Wilhelm M. schrieb: > >> Und wie stellst Du das sicher, wenn alles ein double ist? > > Die Magie des SI-Systems gewährleistet das schon von selber. C kann aber kein SI-System. Du kannst es nur per Konvention bestimmen, dass Entfernung in Angström gemessen wird. Ob Deine Programmierer die richtigen Umrechnungsfaktoren verwenden, kannst Du nicht sicher sein. > Sicher kann > man auch aus Versehen Zeit durch Weg teilen, wenn man Geschwindigkeit > will, aber erstens ist das kein relevantes Szenario, und zweitens fällt > sowas im Test mit Sicherheit auf - wenn nicht, hat man noch ganz andere > Probleme. Doch, genau so etwas ist ein Problem. Und Du kannst es verhindern, weil es einfach nicht kompiliert. >> Richtig ist, sich ein Typ-System zu schaffen > > Ja, Leute mit starkem Hang zu DSLs würden das tun. Es löst allerdings > kein relevantes Problem, denn z.B. der Verlustder Mars-Sonde wäre schon > verhindert worden, wenn alle überall mit demselben System gerechnet > hätten. Haben sie aber nicht, weil der Compiler sie dazu nicht gezwungen hat. Due drehst Dich im Kreis mit Deinen Aussagen. @Wilhelm M.: Um dies zu verstehen, muß man sich weiter in die Sprache reinlehnen, als die meisten hier bereit sind. Da kann ich dann sogar verstehen, daß man die Vorzüge nicht wahrnimmt. Vielleicht kann man schlicht nicht Glauben, was da möglich ist. Oder es ist halt doch zu kompliziert für NOP's.
Gast
#5423751
Wilhelm M. schrieb: > Du kannst es nur per Konvention bestimmen, dass Entfernung in Angström > gemessen wird. Angström ist keine SI-Einheit. > Ob Deine Programmierer die richtigen Umrechnungsfaktoren > verwenden, kannst Du nicht sicher sein. Du kannst nie sicher sein, daß Deine Programmierer irgendwas richtig machen. Nichtmal in ADA. > Doch, genau so etwas ist ein Problem. Ein Spielzeugproblem. Das reale Beispiel, was ich nannte, wäre schon durch Konsistenz im Projekt verhindert worden. Carl D. schrieb: > Oder es ist halt doch zu kompliziert für NOP's. Damit, daß die Abstraktion von C++ eher Obfuscation ist, stehe ich nicht alleine. Wenn Du schon auf der persönlichen Schiene argumentieren willst - da ist z.B. jemand, der den Kernel für ein recht prominentes OS entwickelt hat. Aber der ist im Vergleich zu Dir natürlich auch nur ein Armleuchter, schon klar. Carl D. schrieb: > @Wilhelm M.: > Um dies zu verstehen, muß man sich weiter in die Sprache reinlehnen, als > die meisten hier bereit sind. Da kann ich dann sogar verstehen, daß man > die Vorzüge nicht wahrnimmt. Vielleicht kann man schlicht nicht Glauben, > was da möglich ist. Oder es ist halt doch zu kompliziert für NOP's. Wahrscheinlich hast Du recht :-( Daher der Spruch: "stop teaching C", den ja auch viele falsch verstehen. Die Kernelemente in der Programmierung sind ADTs, aber C "lehrt" eine Denkweise von der technischen Repräsentation her und bürdet dem Programmierer die Last der Interpretation auf. Leider verliert man dadurch eben vieles von dem, was man eigentlich die Maschine machen lassen kann / will. Nop schrieb: > Ein Spielzeugproblem. Das reale Beispiel, was ich nannte, wäre schon > durch Konsistenz im Projekt verhindert worden. Und wie? Durch große Poster an der Wand? Durch eine Project-Charta? Mach doch bitte einmal die Mühe, und denke darüber nach, was ich oben gesagt habe. Nop schrieb:. > > Damit, daß die Abstraktion von C++ eher Obfuscation ist, stehe ich nicht > alleine. Wenn Du schon auf der persönlichen Schiene argumentieren willst > - da ist z.B. jemand, der den Kernel für ein recht prominentes OS > entwickelt hat. Aber der ist im Vergleich zu Dir natürlich auch nur ein > Armleuchter, schon klar. Der hat dafür gute Gründe, die ich nachvollziehen kann. Die sind aber nicht "C++ ist zu kompliziert", sondern technischer Art im Umfeld Kernel-Entwicklung. Das ist die gleiche Argumentsweise, 5worte aus 5Seiten Text picken, wie weiter oben stand "geht nicht bei AVR", ohne daß der Schreiber die GCC Doku nur ansatzweise verstanden hatte. Er, der große Unbenannte bezieht sich auf einen Teilbereich, Exceptions, den man nicht nutzen muß. Auf AVR's gibt es keine Exceptions, aber vieles ander, was das Leben erleichtern kann. Aber, und da muß ich sogar Moby recht geben, es geht auch in Assembler. Wenn man's braucht.
Gast
#5423767
Wilhelm M. schrieb: > Du möchtest gerne Vielleicht solltest Du ne Nacht drüber schlafen, und morgen nach einem Kaffee nochmal lesen... Wilhelm M. schrieb: > distance = 13_km; Die ganze Diskussion zum rechnen mit Einheiten (und entsprechende Programmiersprachen) ist übrigens älter als C.
Gast
#5423771
Wilhelm M. schrieb: > Und wie? Durch große Poster an der Wand? Wenn es das ist, was Du unter einer Projekt-Spezifikation verstehst, dann schon. Carl D. schrieb: > Der hat dafür gute Gründe, die ich nachvollziehen kann. Die sind aber > nicht "C++ ist zu kompliziert", sondern technischer Art im Umfeld > Kernel-Entwicklung. Beileibe nicht nur - und zudem ist das Argument mit den Exceptions auch Unsinn, weil man die nicht benutzen MUSS. Es wird aber indirekt doch ein Schuh draus, denn sobald man C++ benutzt, wird es ein ständiger Abwehrkampf, weil irgendwelche Freaks immer eine Ausrede finden, wieso sie ihr Lieblingsfeature einbauen müssen. Das Ergebnis, wenn man nicht konsequent Subsetting betreibt und das auch durchsetzt, ist eine unwartbare Codebasis. Du unterschlägst außerdem auch seine Kommentare zu STL und Boost, die in genau diese Richtung gehen. Und natürlich, daß er ganz bewußt keine Leute zur systemnahen Programmierung, und auch nicht für Git, haben wollte, sondern Leute, die reale Computer auf Bytelevel programmieren können. Er drückte es so aus, selbst wenn man durch Verwendung von C lediglich C++-Programmierer fernhalte, sei allein das schon den Einsatz von C wert. Wenn ich mir hier so manches durchlese, hat Torvalds das zwar auf seine liebenswerte Weise verpackt, aber es steckt ein wahrer Kern dahinter. Wilhelm M. schrieb: > Nop schrieb: > >> Ein Spielzeugproblem. Das reale Beispiel, was ich nannte, wäre schon >> durch Konsistenz im Projekt verhindert worden. > > Und wie? Durch große Poster an der Wand? Durch eine Project-Charta? > > Mach doch bitte einmal die Mühe, und denke darüber nach, was ich oben > gesagt habe. Wer noch nie gesehen hat, daß der Compiler sagt "Apfel durch Birnen ist keine erlaubte Operation", der wird das nie für möglich halten. Aber mit den Worten des Herrn Schubert: "ich kann mich nicht um alles kümmern!" Nop schrieb: > Wilhelm M. schrieb: > >> Und wie? Durch große Poster an der Wand? > > Wenn es das ist, was Du unter einer Projekt-Spezifikation verstehst, > dann schon. > > > Carl D. schrieb: > >> Der hat dafür gute Gründe, die ich nachvollziehen kann. Die sind aber >> nicht "C++ ist zu kompliziert", sondern technischer Art im Umfeld >> Kernel-Entwicklung. > > Beileibe nicht nur - und zudem ist das Argument mit den Exceptions auch > Unsinn, weil man die nicht benutzen MUSS. Es wird aber indirekt doch ein > Schuh draus, denn sobald man C++ benutzt, wird es ein ständiger > Abwehrkampf, weil irgendwelche Freaks immer eine Ausrede finden, wieso > sie ihr Lieblingsfeature einbauen müssen. Das Ergebnis, wenn man nicht > konsequent Subsetting betreibt und das auch durchsetzt, ist eine > unwartbare Codebasis. . > Du unterschlägst außerdem auch seine Kommentare zu STL und Boost, die in > genau diese Richtung gehen. Man findet auch C-Bibliotheken, die man missbrauchen. > Und natürlich, daß er ganz bewußt keine > Leute zur systemnahen Programmierung, und auch nicht für Git, haben > wollte, sondern Leute, die reale Computer auf Bytelevel programmieren > können. Er drückte es so aus, selbst wenn man durch Verwendung von C > lediglich C++-Programmierer fernhalte, sei allein das schon den Einsatz > von C wert. Das klingt eher nach Stuhl festhalten. Angst ist ein schlechter Ratgeber. > Wenn ich mir hier so manches durchlese, hat Torvalds das zwar auf seine > liebenswerte Weise verpackt, aber es steckt ein wahrer Kern dahinter. Hoffentlich sagt ihm keiner, daß sein C-Code von C++-Programmen übersetzt wird. Wahlweise GCC oder clang. Es scheint also möglich große Software-Pakete in C++ zu schreiben. Nur offenbar nicht überall und mit jedem Projektleiter. Muß man ja auch nicht. Darf man aber unbemecktert können dürfen. Carl D. schrieb: > Hoffentlich sagt ihm keiner, daß sein C-Code von C++-Programmen > übersetzt wird. Autsch... ---- https://madnight.github.io/githut/#/pull_requests/2018/1 Was will man noch diskutieren? Die Sprache der Spachen ist.... JavaScript Heiko L. schrieb: > Carl D. schrieb: >> Hoffentlich sagt ihm keiner, daß sein C-Code von C++-Programmen >> übersetzt wird. > > Autsch... Falls das ein kritisches ätsch war: clang immer schon, GCC seit Version 6 (WIMRE) Beim letzten hab ich dem erst heut wieder zugeschaut, wie er sich selber übersetzt. Unter dem Name g++ gestartet. Carl D. schrieb: > Beim letzten hab ich dem erst heut wieder zugeschaut, wie er sich selber > übersetzt. Unter dem Name g++ gestartet. Ja, und? Ist doch alles das selbe Backend. Und das besteht aus verdächtig vielen Dateien mit .c-Endung. Die Rationale ist da auch ganz einfach: Zum Bootstrappen braucht man einen Compiler. Und ein C-Compiler ist in Assembler um einiges leichter zu schreiben....
Gast
#5423787
Mal was anderes - das Forum braucht abartig lange, um diesen Thread zu laden, und das ist auch bei anderen langen Threads so. Von "klick" bis "Forum springt zum ersten neuen Beitrag" vergehen mehrere Sekunden. Nur bei mir, oder geht Euch das auch so? > Nur bei mir, oder geht Euch das auch so?
Bei mir ist alles normal.
Beitrag #5423789 wurde von einem Moderator gelöscht.
Gast
#5423790
Heiko L. schrieb: > Die Rationale ist da auch ganz einfach: Zum Bootstrappen braucht man > einen Compiler. Da kann man heute aber auch einfach einen Crosscompiler von irgendeiner anderen Plattform nehmen. Heiko L. schrieb: > Carl D. schrieb: >> Beim letzten hab ich dem erst heut wieder zugeschaut, wie er sich selber >> übersetzt. Unter dem Name g++ gestartet. > > Ja, und? Ist doch alles das selbe Backend. Und das besteht aus > verdächtig vielen Dateien mit .c-Endung. Es gibt noch "etwas" Code zwischen Parser und Backend. Der macht die ganze Optimierung und ist C++. Aber muß ich nicht weiter diskutieren. > Die Rationale ist da auch ganz einfach: Zum Bootstrappen braucht man > einen Compiler. Und ein C-Compiler ist in Assembler um einiges leichter > zu schreiben.... Hä?? Was hat das mit dem Thema zu tun? Ich brauche kein Bootrtapp, meine Kiste hat einen lauffähigen GCC, der sich selbst übersetzen kann. Und das von mir benötigte Bachend ist auch schon in der Standard-Source drin. Oder ist das Füllmaterial? Nop schrieb: > Heiko L. schrieb: > >> Die Rationale ist da auch ganz einfach: Zum Bootstrappen braucht man >> einen Compiler. > > Da kann man heute aber auch einfach einen Crosscompiler von irgendeiner > anderen Plattform nehmen. Richtig. Dann muss die Wahl der Sprache wohl noch einen anderen Grund haben. Wilhelm M. schrieb: > Und Du empfiehlst wahrscheinlich auchbool rtc = is_even(x); > if (rtc) { > ... > } > > zu schreiben statt if (is_even(x)) { > ... > } > > nehme nun ich an. Nein. Das ist doch nur ein simples if und kein switch. Der return-Wert kann ja nur 2 Werte annehmen. Wieso schiebst Du mir so etwas unter? Ich persönlich rufe auch triviale Funktionen innerhalb von C-Kontrollstrukturen wie if und switch auf. Zum Beispiel ist das simple "Kopierprogramm" von K&R, welches im Buch bereits kurz nach das "Hello, World" aufgeführt wird, einfach genial:
Die Zuweisung (inkl. Funktionsaufruf!) innerhalb der Bedingung löst genau das Problem, das hier andere Programmiersprachen mit while-Schleifen haben. Wäre so eine Zuweisung nicht möglich, müsste man umständlich schreiben:
Hier wäre der getchar()-Aufruf doppelt. oder als do-while-Schleife:
Hier wäre die Abfrage doppelt. Zurück zum Thema: Du fragtest oben nach Vorteilen, die Funktion nicht in den switch() zu schreiben. Ich hatte Dir lediglich einige genannt, die unter Umständen vorteilhaft sein können. Deine Schlussfolgerung, dass ich persönlich grundsätzlich keine Funktionsaufrufe innerhalb von if, while, switch mache, ist jedoch ziemlich weit hergeholt und auch unzutreffend. Ich kann Dir versichern: Wenn die Funktion bzgl. Aufruf und Semantik hinreichend trivial ist, rufe ich sie auch innerhalb switch() auf. ;-) Also: Ich mache keine Religion daraus. Deine sportliche Anstrengung, den Scope von Variablen möglichst klein zu halten, um Wiederverwendung derselben auszuschließen, in allen Ehren. Aber das ist eher eine Frage der Disziplin des Programmierers, nicht der Programmiersprache. P.S. Zu meiner Person: Ich programmiere seit 1984 in C unter UNIX und habe in den 90ern auch viele Jahre in C++ programmiert. Den Stroustrup habe ich damals dafür rauf und runtergeackert. Ich mag beide Sprachen. Aber ich würde niemals wegen einer so simplen Frage, wie sie der TO gestellt hat, auf die Idee kommen, ihm den Wechsel von C auf C++ anzuraten. Das ist nicht nur kontraproduktiv, sondern auch abschreckend. Du erreichst mit Deiner "Missionarsarbeit" durchaus Ablehnung, weil Du ziemlich hartnäckig sein kannst. Die Bezeichnung "SPAM", die hier gefallen ist, ist da nicht ganz unzutreffend. Wer will auch alle paar Stunden einen Zeugen Jehowas an der Türe klopfen hören, nur weil er gesehen hat, dass ich täglich an einer Kirche vorbeigehe? Mit Tellerrändern, die hier auch aufgeführt wurden, hat das ebenso überhaupt nichts zu tun. Man muss aber nicht immer direkt ein Flugzeug chartern, wenn man beim Aldi einkaufen gehen will.
Gast
#5424007
Frank M. schrieb: > Ich kann Dir versichern: Wenn die Funktion bzgl. Aufruf und Semantik > hinreichend trivial ist, rufe ich sie auch innerhalb switch() auf. ;-) Aha. Es soll ja auch Leute geben, die schachteln gleich 3 oder sogar 4 (vier) Funktionen ineinander. Boooaaaaaaa! :)
Gast
#5424025
batman schrieb: > Aha. Es soll ja auch Leute geben, die schachteln gleich 3 oder sogar 4 > (vier) Funktionen ineinander. Boooaaaaaaa! :) Nennt sich "functional programming". ;-)
Gast
#5424040
batman schrieb: > Aha. Es soll ja auch Leute geben, die schachteln gleich 3 oder sogar 4 > (vier) Funktionen ineinander. Boooaaaaaaa! :) Habe letztens folgenden Ausdruck verfasst:
Gab auch witzige Kommentare....
Gast
#5424044
Arduino F. schrieb: > Gab auch witzige Kommentare.... Zurecht. Carl D. schrieb: > Das ist die gleiche Argumentsweise, 5worte aus 5Seiten Text picken, wie > weiter oben stand "geht nicht bei AVR", ohne daß der Schreiber die GCC > Doku nur ansatzweise verstanden hatte. Gut, dann korrigiere ich: Computed Goto wird auf AVR-GCC nur eingeschränkt unterstützt. Und nun? Wer den vollen Umfang nutzen will, rennt gegen eine Wand. Wer ein Subset nutzen will, muss vorher untersuchen, ob das korrekt implementiert ist - UND DAS IST ARCHITEKTUR-SPEZIFISCH. Klar? Frank M. schrieb: > Ich persönlich rufe auch triviale Funktionen innerhalb von > C-Kontrollstrukturen wie if und switch auf. Zum Beispiel ist das simple > "Kopierprogramm" von K&R, welches im Buch bereits kurz nach das "Hello, > World" aufgeführt wird, einfach genial: >
Ich habe das Snippet, was Du als geniales Stück Code bezeichnest, einmal zu einem Miniprogramm ergänzt, wie Du es evtl. auch gemacht hättest:
Natürlich ist Dir und vielen anderen hier als sehr erfahrende C-Gurus sofort klar, was hier abläuft. Schaut man aber mal genau hin, so stellt man fest, dass es doch schlampig umgesetzt ist. Und deswegen halte ich dieses Programm als einführendes Beispiel für ziemlich ungeeignet. Und zwar aus den folgenden Gründen. Ich bin jetzt etwas sehr pingelig - zugegeben -, aber ich will das eigentliche Problem deutlich machen. Und ja, dies ist kein Spezifikum von C / libc, sondern wir finden es auch in C++ / libstdc++ wieder, vor allem in pre-C++11-Code. Aber man kann es eben besser machen. Und das sollte der Anspruch sein, wenn man solche Diskussionen wie in diesem Thread hat. Es geht hier nicht um Missionierung, sondern darum, was den Kern der Programmierung ausmacht. 1) Es wird in main() im äußeren Block die Variable c des Typs int definiert und mit EOF initialisiert. Gut, das bedeutet, dass der Inhalt von c als ganzzahliger, vorzeichenbehafteter numerischer und semantikloser Typ deklariert wird, der den lokalen Zustand des in main() realisierten Algorithmus repräsentiert. Ich erwarte also einen arithmetischen Umgang mit c. Die Initialisierung mit EOF ist aber schon recht zweifelhaft. "EOF: integer constant of type int and negative value" steht in der Doku der libc. Bedeutung von EOF: end-of-file. Was hat dieser Sentinel-Wert mit ganzzahliger Arithmetisch zu tun? Was würde etwa (EOF + 42) bedeuten? 2) Der Gültigkeitsbereich der Variable c ist der Funktionsblock main(). Auf dieser Ebene wird c aber gar nicht mehr verwendet. Hat also der Ersteller des Codes hier etwas vergessen? Ist das Programm gar fehlerhaft? Das ist auf den schnellen Blick nicht zu erkennen. Das ist verwirrend. 3) Es wird "int getchar()" aufgerufen. Die Doku sagt, es wird ein Zeichen von stdin gelesen. Soweit so gut: aber, warum ist der Typ der Funktion dann int und nicht etwa char, unsigned char, oder sonst was? Ich möchte doch ein Zeichen lesen. Es gibt die Möglichkeit, dass der Name getchar() einfach nicht zur Semantik passt und besser getNumber() heissen sollte. Das könnte den Typ int erklären und ich könnte evtl. Zahlen im Wertebereich eines ints von stdin parsen. Oder es wird ein UTF-16 o.ä. Zeichen gelesen? 4) Genauere Betrachtungen ergeben, das der Typ von getchar() nur deswegen int ist, damit der negative Wert des Sentinels EOF repräsentiert werden kann. Auch das ist sehr undurchsichtig. Ich habe den Typ int für ein Zeichen + Sentinel. Das könnte bedeuten, dass von den mindestens 2^16 Werten des int nur (2^7 + 1) bzw. (2^8 + 1) zulässig sind. Alles andere sind eher trap-representations. Warum sollte ich mit dem Wert von getchar() Berechnungen wie (3 * c + 300) / 42 anstellen können. Unklar. 5) getchar() sollte aber die Semantik besitzen: liefere ein Zeichen, wenn es da ist, oder etwas ungültiges bzw. nichts, wenn ein Fehler auftrat. Ich brauche also einen Datentyp, mit dem ich jedes gültige Zeichen und den ungültigen Zustand repräsentieren kann. Arithm. Operationen für Zeichen sind Unsinn. Operationen zur Konvertierung in korrespondierende Klein-/Großbuchstaben sinnvoll. 6) Bei "int putchar(int)" ergibt sich dasselbe Bild: warum ist der Argumenttyp ein int? Ich möchte doch ein Zeichen ausgeben. Oder gibt putchar(int) den int-Wert als ganze vorzeichenbehaftete Zahl zur Basis 10 aus? Der Name putchar und der Argumenttyp widersprechen sich auch hier. 7) Der Wert von putchar() wird eigentlich nur gebraucht, um Miss-/Erfolg anzuzeigen. Zwei Zustände, dafür gibt es bool. Man fragt sich sofort, welche Werte können denn noch auftauchen? Und welche Bedeutung haben sie? Warum sollte ich auch hier mit dem Wert von putchar() Arithmetik betreiben können? Die Doku sagt aus, das der Argumentwert intern auf unsigned char gewandelt wird und dieser Wert dann zusammen mit ggf. dem Sentinel auftauchen kann. Mindestens verwirrend. Man kann daraus im wesentlichen zwei Sachen lernen. I) Datentypen sind dazu da, die notwendigen Entitäten im Code möglichst exakt abzubilden. Entsprechen die Wertebereiche und/oder möglichen Operationen nicht den Erwartungen, ist das mindestens sehr verwirrend. II) Namen sind nicht unwesentlich. Ein Code ist nur dann klar, wenn I und II konsistent zueinander passen. Bei "int getchar()" und "int putchar(int)" ist das nicht gegeben. Zudem ist int als unspezifischer Typ zur Darstellung eines Zeichens in einem 7- oder 8-bit-Code unsinnig. Die für manche nun unangenehme Erkenntnis ist, dass wir I in C nicht zufriedenstellend erreichen können, und damit die wichtige Kombination aus I und II in C scheitert. Besserer Code kann nur gelingen, wenn a) Datentypen entsprechend der Problemdomäne geschaffen werden können (UDT). b) Diese Datentypen (UDT) durch sinnvolle Wahl der möglichen Operationen (Erzeugung, Kopier- und Konvertierungsverhalten, intrinsische und zusätzliche Operationen, Zerstörung, etc.) und Namen eine Semantik bekommen. c) Die UDT möglichst nahtlos in die restliche Sprache eingebettet sind. d) Die Sprache so gestaltet ist, das die Intention des Autors optimal wiedergegeben werden kann. Die Sprache C++ macht das mittlerweile zu einem großen Maße ganz gut (das war aber vor C++11 nicht so): i) Man kann eigene Typen erstellen und sie fast vollständig in die Struktur der Sprache einbetten, d.h die instrinsichen Operationen der Sprache und zusätzliche ermöglichen oder nicht, etc. Dabei drängt man die Bedeutung der intrinsichen Typen soweit wie möglich zurück, denn intrinsiche Typen entfalten kein Semantik (Beispiel: double als Meter oder Kilometer). ii) Dabei kann man die Mächtigkeit der Typen vollkommen steuern: was ist wie erzeugbar, was kann man kopieren oder nur verschieben, was passiert beim Zerstören, welcher Wertebereiche / Zustände sind zulässig, welche Konvertierung sollen ausführbar sein, etc. iii) Durch Meta-Programmierung können Datentypen ausgehend von den Eigenschaften anderer Datentypen ermittelt werden, etwa: was ist der kleinste aber ausreichende Typ für die Indizierung aller Elemente in einem Container (hat in diesem o.g. Beispiel allerdings keine Bedeutung). iv) ... Als C++-Programm könnte das obige Beispiel etwa so aussehen, z.B. für 7-Bit Ascii-Zeichen oder unspezifische Bytes:
Zum nachvollziehen ist dazu folgendes noch notwendig:
Wobei die Verwendung des std::optional<> zur Externalisierung des invaliden Zustandes bei AsciiChar natürlich nicht notwendig ist (man hätte auch einen Typumwandlungsoperator nach bool schreiben können), aber bei std::byte praktischer (falls man den DT std::byte aus der libstdc++ verwendet). Der generische DT std::optional<> ist sinnvoll in die Sprache eingebettet, folgt er doch dem Zeiger-Idiom (Zeigertypen sind die einzigen Typen, die einen ungütigen Wert besitzen, und dienen deswegen als Orientierung mit der impl. Wandlung nach bool). Wie man sieht, kommen hier nur wenige Komponenten der objekt-orientierten Programmierung im engeren Sinn zur Anwendung. Wohl aber 1) werden UDT definiert, die möglichst genau dem Einsatzzweck entsprechen (mögliche Werte, ungültiger Zustand), 2) die möglichen Operationen der Typen wird genau festgelegt (Elementfunktionen, freie Funktionen), 3) die Expressivität auf der Anwendungsseite wird durch 3.1) Einschränkung des Gültigkeitsbereiches 3.2) Funktionsüberladung 3.3) generischen Code und Typinferenz gesteigert. 4) die Sicherheit wird erhöht, weil unsinnige Operationen nicht möglich sind. Natürlich ist das obige noch nicht optimal, aber m.E. schon ein Schritt in die richtige Richtung. Summa summarum ist also der Schritt von gewöhnlichem C zur dieser Art von prozeduralem, expressivem Code in C++ nicht besonders groß. (Ups, Ende, ICE hält gleich ...)
Beitrag #5424457 wurde von einem Moderator gelöscht.
Beitrag #5424593 wurde von einem Moderator gelöscht.
Wilhelm M. schrieb: > Aber man kann es eben besser machen. Und das sollte der Anspruch > sein, wenn man solche Diskussionen wie in diesem Thread hat. In erster Linie sollte man es richtig machen. Und das heißt, dass man die zu verwendende API auch korrekt verwendet - oder eine bessere API entwickelt. > 1) Es wird in main() im äußeren Block die Variable c des Typs int > definiert und mit EOF initialisiert. Sinnvoll. > Ich erwarte also einen arithmetischen Umgang mit c. [...] > Bedeutung von EOF: end-of-file. Was hat dieser Sentinel-Wert > mit ganzzahliger Arithmetisch zu tun? Nichts. > Was würde etwa (EOF + 42) bedeuten? Ist eine Zahl. Kann positiv oder negativ sein. Ist implementation-defined und entsprechend dokumentiert. > 2) Der Gültigkeitsbereich der Variable c ist der Funktionsblock main(). > Auf dieser Ebene wird c aber gar nicht mehr verwendet. Das tut mir aber Leid. Mach einen Block drum, wenn's dich stört. > Hat also der Ersteller des Codes hier etwas vergessen? > Ist das Programm gar fehlerhaft? Die Frage gilt für jeden Code. > Das ist auf den schnellen Blick nicht zu erkennen. Das ist > verwirrend. Wenn du von so einem Trivialprogramm verwirrt bist, dann sind domänenspezifische Programmiersprachensubsets vielleicht eher was für dich? > 3) Es wird "int getchar()" aufgerufen. Die Doku sagt, es wird ein > Zeichen von stdin gelesen. Soweit so gut: aber, warum ist der Typ der > Funktion dann int und nicht etwa char, unsigned char, oder sonst was? Weil du die Doku nicht ordentlich gelesen hast. > Ich möchte doch ein Zeichen lesen. Es gibt die Möglichkeit, dass der > Name getchar() einfach nicht zur Semantik passt und besser getNumber() > heissen sollte. Der Name passt zur Semantik, du definierst dir nur gerade irgendwas zurecht. > Das könnte den Typ int erklären und ich könnte evtl. > Zahlen im Wertebereich eines ints von stdin parsen. Zahlen und Zeichen sind verschiedene Dinge. > Oder es wird ein UTF-16 o.ä. Zeichen gelesen? Die Doku redet nicht von UTF-16, also wird es höchstwahrscheinlich auch keins sein. > 4) Genauere Betrachtungen ergeben, das der Typ von getchar() nur > deswegen int ist, damit der negative Wert des Sentinels EOF > repräsentiert werden kann. Auch das ist sehr undurchsichtig. Das ist nicht undurchsichtig, sondern schlicht so definiert. Da kannst du auf und niedrig hüpfen oder deine eigene API bauen, aber du wirst dieses Problem auch irgendwie lösen müssen (zweiter Rückgabewert, Exceptions o.ä.). Sämtliche deiner Lösungen werden auf Maschinen mit mehr als 8 Bit weniger effizient sein. > Ich habe den Typ int für ein Zeichen + Sentinel. > Das könnte bedeuten, dass von den mindestens 2^16 Werten > des int nur (2^7 + 1) bzw. (2^8 + 1) zulässig sind. Korrekt. > Alles andere sind eher trap-representations. Warum sollte ich mit > dem Wert von getchar() Berechnungen wie (3 * c + 300) / 42 anstellen > können. Unklar. Du kannst solche Berechnungen genau dann erledigen, wenn getchar() != EOF ist. Und wozu du sie anstellen wolltest, liegt an deinem Problem, nicht an deiner Wunschlösung. > 5) getchar() sollte aber die Semantik besitzen: liefere ein Zeichen, > wenn es da ist, oder etwas ungültiges bzw. nichts, wenn ein Fehler > auftrat. Aha. > Ich brauche also einen Datentyp, mit dem ich jedes gültige > Zeichen und den ungültigen Zustand repräsentieren kann. Also mindestens 8 Bit plus Flag oder mindestens 9 Bit. > Arithm. Operationen für Zeichen sind Unsinn. Warum? Sie sind zumindest für Kryptographie sinnvoll, auch wenn du nicht auf ASCII stehst. > Operationen zur Konvertierung in > korrespondierende Klein-/Großbuchstaben sinnvoll. Was ist mit Zeichen, die keine oder keine eindeutige Repräsentation haben? Wie sieht es mit locale-Unterstützung aus (I <-> i, oder doch lieber I <-> ı und İ <-> i wie im Türkischen)? Und willst du Unicode so tief in die Sprache einbauen, dass es auch für Aramäisch funktioniert? Auf 8 Bit-Systemen mit 4 KB Flash? > 6) Bei "int putchar(int)" ergibt sich dasselbe Bild: warum ist der > Argumenttyp ein int? Orthogonalität, auch bekannt als Konsistenz. > 7) Der Wert von putchar() wird eigentlich nur gebraucht, um Miss-/Erfolg > anzuzeigen. Zwei Zustände, dafür gibt es bool. Man fragt sich sofort, > welche Werte können denn noch auftauchen? Jemand, der die Programmiersprache verstanden hat, weiß sofort, dass die Wahrheitswerte auf "gleich null" und "ungleich null" herauslaufen. Du willst die Sprache für jemanden verständlich machen, der eine andere Sprache versteht, aber nicht bereit ist, sich mit dieser Sprache zu befassen. Gratuliere. Aber dann nimm halt die andere Sprache und gut ist? > I) Datentypen sind dazu da, die notwendigen Entitäten im Code möglichst > exakt abzubilden. Entsprechen die Wertebereiche und/oder möglichen > Operationen nicht den Erwartungen, ist das mindestens sehr verwirrend. Also ich erwarte in aller Regel das, was in der Doku steht... > II) Namen sind nicht unwesentlich. getchar() gibt ein Zeichen zurück, putchar() sendet ein Zeichen, finde ich eindeutig. Dass ein Zeichen hier als "int" definiert ist, weil es alle Zeichen und ein EOF beinhalten kann, ist eine konsistent umgesetze Eigenheit der API. Da finde ich den PHP-Ansatz, alles zueinander inkonsistent zu halten, wesentlich nerviger. > Zudem ist int als unspezifischer Typ zur Darstellung eines Zeichens > in einem 7- oder 8-bit-Code unsinnig. Warum? ASCII ist nunmal ein 7- oder 8-bit-Code... > Die für manche nun unangenehme Erkenntnis ist, dass wir I in C nicht > zufriedenstellend erreichen können, und damit die wichtige Kombination > aus I und II in C scheitert. Das ist eine für dich unangenehme Erkenntnis, weil dein Horizont ungeeignet dafür ist. :-) Andere können damit gut leben. Und ja, mir ist auch klar, dass man es besser machen kann - aber dann muss man die Vorteile von C aufgeben. Und dazu bin ich in bestimmten Bereichen schlicht nicht bereit. Eine Kröte muss ich schlucken. > Natürlich ist das obige noch nicht optimal, aber m.E. schon ein Schritt > in die richtige Richtung. Summa summarum ist also der Schritt von > gewöhnlichem C zur dieser Art von prozeduralem, expressivem Code in C++ > nicht besonders groß. Dein geposter Code ist wesentlich länger als das, was die Definition von "ein Zeichen im Sinne eines Streams ist ein Zeichen oder ein EOF" erlaubt. Dass der Maschinencode im Endeffekt besser sein kann (nicht sein muss), ist eine andere Frage... Wilhelm M. schrieb: > [Unendliche Ausführung über int als Rückgabetyp von getchar()] Du regst Dich auf über die Unzulänglichkeiten, aber wendest diese selbst an: > template<> > std::optional<std::byte> get<std::byte>() { > if (int c = getchar(); c != EOF) { > return std::byte(c); Das ist jetzt nicht wahr, oder? Ich lese da: int c = getchar(); und c != EOF; Du legst also lediglich um die vermeintlichen Unzulänglichkeitenen nur ein rosa-rotes Mäntelchen drum und verkaufst das dann als ultimative "Verbesserung". Klasse! Sorry, damit machst Du Dich komplett unglaubwürdig. Dein "verbesserter Code" ist für einen potentiellen C- nach C++-Umsteiger: - länger - komplizierter - umständlicher - nicht schneller - und vor allen Dingen: ABSCHRECKEND. So sind Deine Missionierungsversuche von vornherein zum Scheitern verurteilt. Und damit EOD für mich. Du solltest in den Vertrieb gehen. Als Verkäufer machst Du Dich ganz gut.
Gast
#5424951
Wilhelm M. schrieb: > Als C++-Programm könnte das obige Beispiel etwa so aussehen, z.B. für > 7-Bit Ascii-Zeichen oder unspezifische Bytes: Und genau das ist der Grund, wieso ein Torvalds keine C++-Programmierer an Bord haben will. Weil die aus ganz einfachen Routinen einen totalen Clusterfsck veranstalten, nur weil sie können.
Gast
#5425001
Übrigens, ein ganzes Projekt in so einem Stil geschrieben, mit dann hunderten solcher sinnloser Abstraktionen, das ist schlichtweg unwartbarer write-only-Code. Niemand außer dem ursprünglichen Autoren wird durch so einen Wust noch durchsteigen, und wenn der aus dem Projekt draußen ist, kann man es bloß noch wegwerfen. Mit Glück hat man eine Projektführung, die solche Tendenzen rechtzeitig erkennt und das stoppt, im Extremfall auch durch Entfernen solcher "code astronauts" aus dem Projekt. getchar.c:
Compilieren:
Ausführen: Kopieren von 1000 MB von /dev/zero nach /dev/null:
Jetzt das Gleiche mit Wilhelms Lösung: getchar.cc:
Compilieren:
Ausführen: Kopieren von 1000 MB:
Fazit: Das simple Kopieren von Zeichen von links nach rechts dauert nun mehr als doppelt(!) so lang. Aber Hauptsache, das Programm sieht geil aus.
Gast
#5425122
Frank M. schrieb: > Fazit: Das simple Kopieren von Zeichen von links nach rechts dauert nun > mehr als doppelt(!) so lang. Aber Hauptsache, das Programm sieht geil > aus. Lass denn Compiler etwas arbeiten (-O2) und schon ist das Ergebnis identisch. mh schrieb: > Lass denn Compiler etwas arbeiten (-O2) und schon ist das Ergebnis > identisch.
Stimmt, bis auf ca. 5% ist er dran. Okay.
Gast
#5425162
Frank M. schrieb: > Stimmt, bis auf ca. 5% ist er dran. Okay. Bei meinem Test ist die C++ Variante 3% schneller... Mikrobenchmarks mit "time" sind halt nicht sehr verlässlich. Man sollte auch bedenken, dass deine C Variante weniger Arbeit erledigen muss als die C++ Variante, da der Rückgabewert von putchar ignoriert wird. Korrigiert man das (siehe 2. Code im Post won W.M.), dann liefert der Compiler für C und C++ ein identisches Ergebnis. mh schrieb: > Frank M. schrieb: >> Stimmt, bis auf ca. 5% ist er dran. Okay. > > Bei meinem Test ist die C++ Variante 3% schneller... Mikrobenchmarks mit > "time" sind halt nicht sehr verlässlich. > > Man sollte auch bedenken, dass deine C Variante weniger Arbeit erledigen > muss als die C++ Variante, da der Rückgabewert von putchar ignoriert > wird. Korrigiert man das (siehe 2. Code im Post won W.M.), dann liefert > der Compiler für C und C++ ein identisches Ergebnis. Der dazu idiomatische C++-Code
ist übrigens genauso schnell wie die C-Variante (oder die andere C++-Variante).
Gast
#5425295
Wilhelm M. schrieb: > Der dazu idiomatische C++-Code > int main(){ > Console<std::byte> console; > std::copy(std::begin(console), std::end(console), console.obegin()); > } > > ist übrigens genauso schnell wie die C-Variante (oder die andere > C++-Variante). Aber dafür muss man ja nen template verstehen und selbst programmieren. ;-) mh schrieb: > Wilhelm M. schrieb: >> Der dazu idiomatische C++-Code >> int main(){ >> Console<std::byte> console; >> std::copy(std::begin(console), std::end(console), console.obegin()); >> } >> >> ist übrigens genauso schnell wie die C-Variante (oder die andere >> C++-Variante). > > Aber dafür muss man ja nen template verstehen und selbst programmieren. > ;-) Oh ja, das böse T-Wort ... Deswegen habe ich paar Zeilen für "Console" grad mal weggelassen. Der geneigte Leser mag es grad selbst schreiben. mh schrieb: > Wilhelm M. schrieb: >> Der dazu idiomatische C++-Code >> int main(){ >> Console<std::byte> console; >> std::copy(std::begin(console), std::end(console), console.obegin()); >> } >> >> ist übrigens genauso schnell wie die C-Variante (oder die andere >> C++-Variante). > > Aber dafür muss man ja nen template verstehen und selbst programmieren. > ;-) Man kann aber statt Console<> auch jeden anderen Container nehmen, ohne am Algorithmus etwas ändern zu müssen. Oder umgekehrt jeden Algorithmus aus der STL verwenden kann, der einen Forward-Iterator und einen "Ende-Zeiger", der den "!="-Operator kennt. Aber sicher zuviel Abstraktion, oder? Nicht für jeden. S. R. schrieb: >> Ich erwarte also einen arithmetischen Umgang mit c. [...] >> Bedeutung von EOF: end-of-file. Was hat dieser Sentinel-Wert >> mit ganzzahliger Arithmetisch zu tun? > > Nichts. Richtig. >> Was würde etwa (EOF + 42) bedeuten? > > Ist eine Zahl. Kann positiv oder negativ sein. > Ist implementation-defined und entsprechend dokumentiert. Und deswegen sollte diese Operation auch nicht möglich sein (s.a. Antwort auf die vorige Frage). >> 2) Der Gültigkeitsbereich der Variable c ist der Funktionsblock main(). >> Auf dieser Ebene wird c aber gar nicht mehr verwendet. > > Das tut mir aber Leid. Mach einen Block drum, wenn's dich stört. Man fügt einen weiteren Block ein, nur damit eine Variable in diesem Block sichtbar ist, obwohl sie eigentlich nur in einem inneren Block dazu sichtbar sein sollte? Das ist von hinten durch die Brust ins Auge und ändern am Problem nichts. >> Hat also der Ersteller des Codes hier etwas vergessen? >> Ist das Programm gar fehlerhaft? > > Die Frage gilt für jeden Code. Bei einem Codeabschnitt, der in seiner Struktur schon fragwürdig ist, ist die Wahrscheinlichkeit von Fehlern einfach größer. >> Das ist auf den schnellen Blick nicht zu erkennen. Das ist >> verwirrend. > > Wenn du von so einem Trivialprogramm verwirrt bist, dann sind > domänenspezifische Programmiersprachensubsets vielleicht eher was für > dich? Ein Beispiel ist ein Beispiel und damit per se einfach. Du hast den Punkt nicht erkannt. >> 3) Es wird "int getchar()" aufgerufen. Die Doku sagt, es wird ein >> Zeichen von stdin gelesen. Soweit so gut: aber, warum ist der Typ der >> Funktion dann int und nicht etwa char, unsigned char, oder sonst was? > > Weil du die Doku nicht ordentlich gelesen hast. Und die Doku beschreibt einfach nur einen Mangel: den Widerspruch zwischen dem Typ der Funktion und der Aufgabe der Funktion. In der Doku steht: The obtained character on success or EOF on failure. Die Frage bleibt: warum ein int als Typ? Die Posix-Doku ist da etwas deutlicher. Die man-page von getchar() verweist auf die von getc(), die wiederum verweist auf die von fgetc() und dort steht dann: the fgetc() function shall obtain the next byte as an unsigned char converted to an int Ja, und leider kann der Anfänger auch leicht den Fehler
Auch hier gilt das doch pars pro toto. Denk doch einfach mal einen Schritt weiter. Stell Dir irgendeine beliebige andere Funktion vor:
Die Bedeutung einer Funktion sollte weitestgehend auch ohne Doku klar aus dem Typ und der Signatur hervorgehen: hier lese ich heraus, dass ein Objekt des Typs Data in den Typ uint16_t konvertiert wird. Was ich nicht erfahre ist, was passiert in dem Fall, das die Konversion nicht möglich ist (falsche Format, NULL-Pointer)? Irgendwo steht dann im Kleingedruckten, dass die Konversion aber in ein uint8_t erfolgt und der Typ nur deswegen uint16_t ist, damit ich einen Misserfolg anzeigen kann. Das Pendant dazu
ist viel klarer: eine Referenz ist nicht nullable, um den Fall muss ich mir also keine Gedanken machen. Das eigentliche Ergenbis hat den Typ uint8_t, und per std::optional<> kann ich auch als Ergebnis die leere Menge erhalten (im Fehlerfall). >> Ich möchte doch ein Zeichen lesen. Es gibt die Möglichkeit, dass der >> Name getchar() einfach nicht zur Semantik passt und besser getNumber() >> heissen sollte. > > Der Name passt zur Semantik, du definierst dir nur gerade irgendwas > zurecht. Das erfahre ich aber erst dann, wenn ich etwas mühsam die Doku gelesen habe (s.o.). Der Punkt ist doch, dass ich den Code so aussagekräftig wie möglich gestalten will. >> Das könnte den Typ int erklären und ich könnte evtl. >> Zahlen im Wertebereich eines ints von stdin parsen. > > Zahlen und Zeichen sind verschiedene Dinge. Ja, das versuche ich doch die ganze Zeit klar zu machen. >> Oder es wird ein UTF-16 o.ä. Zeichen gelesen? > > Die Doku redet nicht von UTF-16, also wird es höchstwahrscheinlich auch > keins sein. Höchstwahrscheinlich ... besser wäre, man müsste keine Vermutungen anstellen. >> 4) Genauere Betrachtungen ergeben, das der Typ von getchar() nur >> deswegen int ist, damit der negative Wert des Sentinels EOF >> repräsentiert werden kann. Auch das ist sehr undurchsichtig. > > Das ist nicht undurchsichtig, sondern schlicht so definiert. Es ist schlicht schlecht designed. > Da kannst du auf und niedrig hüpfen oder deine eigene API bauen, aber du > wirst dieses Problem auch irgendwie lösen müssen (zweiter Rückgabewert, > Exceptions o.ä.). Genau, habe ich ja auch gelöst. > Sämtliche deiner Lösungen werden auf Maschinen mit > mehr als 8 Bit weniger effizient sein. Nein, es kommt sogar derselbe Code dabei heraus. >> Alles andere sind eher trap-representations. Warum sollte ich mit >> dem Wert von getchar() Berechnungen wie (3 * c + 300) / 42 anstellen >> können. Unklar. > > Du kannst solche Berechnungen genau dann erledigen, wenn getchar() != > EOF ist. Nein. Ich kann es leider immer: der Compiler verhindert es hier nicht. >> Ich brauche also einen Datentyp, mit dem ich jedes gültige >> Zeichen und den ungültigen Zustand repräsentieren kann. > > Also mindestens 8 Bit plus Flag oder mindestens 9 Bit. Genau. Oder eben 16-Bit. Aber diese 16-Bit will ich doch keinesfalls als vorzeichenbehaftete Zahl interpretieren. Ich möchte den 8-Bit Zeichencode haben und ggf. einen Fehlerzustand. >> Arithm. Operationen für Zeichen sind Unsinn. > > Warum? Sie sind zumindest für Kryptographie sinnvoll, auch wenn du nicht > auf ASCII stehst. Was soll denn das Ergebnis der Multiplikation des Buchstabens A mit dem Buchstaben Z sein? Du meinst eher: Multiplizieren den ASCII-Zeichencode von A mit dem ASCII-Zeichencode von B:
>> Operationen zur Konvertierung in >> korrespondierende Klein-/Großbuchstaben sinnvoll. > > Was ist mit Zeichen, die keine oder keine eindeutige Repräsentation > haben? Ja, genau (s.a. int tolower(int c)). Hier wieder dasselbe Problem ... >> 6) Bei "int putchar(int)" ergibt sich dasselbe Bild: warum ist der >> Argumenttyp ein int? > > Orthogonalität, auch bekannt als Konsistenz. Mmh, Orthogonalität in der Schnittstelle eines Typs ist etwas anderes als Konsistenz in der Doku. Formal habe ich den Datentyp int für vorzeichenbehaftete Ganzzahlen mit mindestens 16-Bit, der die Operationen +,-,*,/, ..., <, <=, ... und auch putchar(), tolower(), ... hat. Wäre es nicht der DT int, sondern etwa ComplexNumber, dann wäre es jedem Anfänger klar, dass etwa <, <=, ... und auch tolower() nicht zur Schnittstelle des DT gehören. Hier aber wird der DT int für etwas hijacked, für das er nicht steht. Nur bei int ist man historisch bedingt bereit eine Ausnahme zu machen, weil C es nicht besser kann. >> 7) Der Wert von putchar() wird eigentlich nur gebraucht, um Miss-/Erfolg >> anzuzeigen. Zwei Zustände, dafür gibt es bool. Man fragt sich sofort, >> welche Werte können denn noch auftauchen? > > Jemand, der die Programmiersprache verstanden hat, weiß sofort, dass die > Wahrheitswerte auf "gleich null" und "ungleich null" herauslaufen. Mmh, ich lese das: jemand, der die Unzulänglichkeiten der Programmiersprache verstanden hat, ... > Du willst die Sprache für jemanden verständlich machen, der eine andere > Sprache versteht, aber nicht bereit ist, sich mit dieser Sprache zu > befassen. Gratuliere. Nein. Ich möchte darauf aufmerksam machen, dass die Sprache C eklatante Mängel hat, die andere Sprachen nicht haben. Zudem existiert eben mit C++ eine Sprache, die einen sehr leichten, schrittweisen Aufstieg ermöglicht, weil ich cherry-picking machen kann: ich bleibe bspw. beim prozeduralen Paradigma wie in C, nehme aber viele Vorteile mit. > Aber dann nimm halt die andere Sprache und gut > ist? Das mache ich ja. Reines C ist für mich keine Option (mehr), weil es einfach nur Nachteile hat. >> I) Datentypen sind dazu da, die notwendigen Entitäten im Code möglichst >> exakt abzubilden. Entsprechen die Wertebereiche und/oder möglichen >> Operationen nicht den Erwartungen, ist das mindestens sehr verwirrend. > > Also ich erwarte in aller Regel das, was in der Doku steht... Das Problem daran ist aber, dass der Compiler die Doku nicht überprüft. Und bekanntlich altert Doku anders als der Code, das ist wie bei Kommentaren. Die Konsequenz daraus ist, dass ich nur dann die Fehlerwahrscheinblichkeit im Code reduziere, wenn der Compiler möglichst viel überprüfen kann. Und das mache ich mit einem starken Typsystem, was aus den notwendigerweise unspezifischen primitiven DT der Sprache domänenspezifische DT mit klarer Semantik erstelle. >> II) Namen sind nicht unwesentlich. > > getchar() gibt ein Zeichen zurück, > putchar() sendet ein Zeichen, > finde ich eindeutig. Du hast hier I) vergessen: der Name passt nicht zur Schnittstelle. > Dass ein Zeichen hier als "int" definiert ist, weil es alle Zeichen > und ein EOF beinhalten kann, ist eine konsistent umgesetze Eigenheit > der API. Kann man so sehen: wenn man den DT int bei getchar() schon missbraucht, dann sollte man es auch bei putchar(int) tun ;-) >> Zudem ist int als unspezifischer Typ zur Darstellung eines Zeichens >> in einem 7- oder 8-bit-Code unsinnig. > > Warum? ASCII ist nunmal ein 7- oder 8-bit-Code... Da widersprichst Du Dir selbst: warum sollte ich auf einer kleinen 8-Bit Plattform ein Zeichen als ein int darstellen. > Andere können damit gut leben. Und ja, mir ist auch klar, dass man es > besser machen kann - Das versuche ich die ganze Zeit zu sagen: man kann es besser machen. > aber dann muss man die Vorteile von C aufgeben. Die wären jetzt in diesem Beispiel welche: ich sehe keinen Einzigen. > Und > dazu bin ich in bestimmten Bereichen schlicht nicht bereit. Eine Kröte > muss ich schlucken. Ich will keine Kröte schlucken, schmeckt mir einfach nicht. Ich esse lieber etwas, was optisch ansprechend und in sich gesund ist, um im Bild zu bleiben. > Dein geposter Code ist wesentlich länger als das, was die Definition von > "ein Zeichen im Sinne eines Streams ist ein Zeichen oder ein EOF" > erlaubt. Das stimmt so nicht, denn Du muss ja berücksichtigen, dass die Definition des Typs AsciiChar und auch die der anderen freien Funktionen Bestandteil einer (besseren) Bibliothek sind, und damit hier nicht mitzählen. Oder möchtest Du die realisierung von getchar() / putchar() aus der libc auch dazu zählen? > Dass der Maschinencode im Endeffekt besser sein kann (nicht > sein muss), ist eine andere Frage... Ich kann nicht für alle Compiler / Plattformen sprechen: er wird aber in vielen Fällen (etwa auch AVR8) identisch sein.
Gast
#5430211
Wilhelm M. schrieb: > The obtained character on success or EOF on failure. > > Die Frage bleibt: warum ein int als Typ? Na vielleicht wollte sich der Autor damals nicht auf 7-Bit ASCII festlegen. Damit kommt ja heute auch nicht mehr weit. Es ist ja auch wirklich kein Problem, so wie ich es oft mache, noch einen kleinen typsicheren Wrapper für eine OO-Sprache drumrumzulegen. In C++ hat man sowieso überall dicke Verkapselungszwiebeln. batman schrieb: > Wilhelm M. schrieb: >> The obtained character on success or EOF on failure. >> >> Die Frage bleibt: warum ein int als Typ? > > Na vielleicht wollte sich der Autor damals nicht auf 7-Bit ASCII > festlegen. Damit kommt ja heute auch nicht mehr weit. Es ist ja auch nicht 7-Bit Ascii, es ist ein Byte-Interface! Das war ja auch nicht wirklich als Frage meinerseits zu verstehen: woher es kommt, ist mir schon klar. Es ist doch auch nur ein Beispiel für ein schlecht gestaltetes Interface, eben weil C keine andere Möglichkeiten hat. > Es ist ja auch > wirklich kein Problem, so wie ich es oft mache, noch einen kleinen > typsicheren Wrapper für eine OO-Sprache drumrumzulegen. In C++ hat man > sowieso überall dicke Verkapselungszwiebeln. Genau das habe ich ja gemacht, weil ich natürlich nicht getchar() neu erfinden wollte, sondern nur das Interface klarer gestalten. Aber das sollte doch auch aus dem ganzen Thread deutlich werden.
Gast
#5430228
Wilhelm M. schrieb: > Genau das habe ich ja gemacht, weil ich natürlich nicht getchar() neu > erfinden wollte, sondern nur das Interface klarer gestalten. Klarer gestalten.. ja nee, ist klar. Tatsächlich hast Du aus einer einfachen Funktion einen unleserlichen Clusterfsck gemacht. Ich will gar nicht erst wissen, wie Deine Funktionen aussehen, die nichttriviale Dinge tun. Wilhelm M. schrieb: > Aber das sollte doch auch aus dem ganzen Thread deutlich werden. Der Thread ging ursprünglich um die Frage, ob man in C (nicht C++) innerhalb des switch() eine Funktion aufrufen könne. Der Thread wurde erfolgreich gekapert. Gratuliere.
Gast
#5430236
Wilhelm M. schrieb: >> Na vielleicht wollte sich der Autor damals nicht auf 7-Bit ASCII >> festlegen. Damit kommt ja heute auch nicht mehr weit. > > Es ist ja auch nicht 7-Bit Ascii, es ist ein Byte-Interface! Wo steht das? Der Rückegabewert ist quasi eine UNION aus Fehlercode und numerischem Zeichencode. batman schrieb: > Der Rückegabewert ist quasi eine UNION aus Fehlercode und numerischem > Zeichencode. Eben. Wie ich oben schon schrieb, hat er lediglich ein rosa-rotes Mäntelchen um getchar() und EOF gewickelt. Da bleibe ich lieber bei getchar(). Da ist in wenigen Minuten ein funktionsfähiges Kopierprogramm, mit CRLF->LF oder LF->CRLF Filter (unix2dos or dos2unix) geschrieben, während Wilhelm noch am Interface tüftelt - ohne irgendeinen funktionalen Vorteil zu bieten. Für jedes Problem das richtige Werkzeug. Es ist unbestritten, dass C++ für bestimmte Aufgaben die bessere Programmiersprache ist. Aber jemanden zu drängen, auf C++ umzusteigen, damit er Funktionen innerhalb switch() aufrufen kann (was in C genauso geht), ist nicht zielführend. Der TO hat sich auch genau an dieser Stelle aus dem Thread ausgeklinkt. batman schrieb: > Wilhelm M. schrieb: >>> Na vielleicht wollte sich der Autor damals nicht auf 7-Bit ASCII >>> festlegen. Damit kommt ja heute auch nicht mehr weit. >> >> Es ist ja auch nicht 7-Bit Ascii, es ist ein Byte-Interface! > > Wo steht das? Nicht explizit: es hängt vom Mode des streams ab. > Der Rückegabewert ist quasi eine UNION aus Fehlercode und numerischem > Zeichencode. Kann man so sehen. Allerdings eben mit dem ganz großen Nachteil, dass es das nicht nicht wirklich als eigener Typ ist, sondern hier ein in missbraucht wird. Daraus resultieren alle weiteren Probleme. Es gibt ja nicht ohne Grund die Fragen zum Thema, was hieran wohl falsch sei:
Wilhelm M. schrieb: > was hieran wohl falsch sei:char c = getchar(); Willst Du so C-Programmierer vor ihrer eigenen Dummheit schützen oder was soll das? Schon im K&R steht drin, dass c vom Typ int sein muss. man getchar Da steht: int getchar(void); Einfacher gehts nicht. Konstruiere doch nicht irgendeinen Programmierer, der ein Blödmann ist. Die gibts überall - und die programmieren nicht alle in C. Wenn Du ein Betätigungsfeld für Deine Mission suchst: Schnapp Dir die zahllosen Arduino-Threads. Die Armen "programmieren" alle in C++, ohne es überhaupt zu wissen. Viele von ihnen haben echt Hilfe nötig. Frank M. schrieb: > batman schrieb: >> Der Rückegabewert ist quasi eine UNION aus Fehlercode und numerischem >> Zeichencode. > > Eben. Wie ich oben schon schrieb, hat er lediglich ein rosa-rotes > Mäntelchen um getchar() und EOF gewickelt. > > Da bleibe ich lieber bei getchar(). Da ist in wenigen Minuten ein > funktionsfähiges Kopierprogramm, mit CRLF->LF oder LF->CRLF Filter > (unix2dos or dos2unix) geschrieben, während Wilhelm noch am Interface > tüftelt - ohne irgendeinen funktionalen Vorteil zu bieten. Ein funktionaler Vorteil sollte doch auch gar nicht dabei heraus kommen. Ein unix2dos in C++ sollte genauso verwendet werden können, wie eins in C oder ... > > Für jedes Problem das richtige Werkzeug. Es ist unbestritten, dass C++ > für bestimmte Aufgaben die bessere Programmiersprache ist. Aber jemanden > zu drängen, auf C++ umzusteigen, damit er Funktionen innerhalb switch() > aufrufen kann (was in C genauso geht), ist nicht zielführend. Der Einstieg in die Diskussion war aber wie Du weißt anderes: es ging nicht um die Möglichkeit, sondern um eine Stilfrage und anschließend, ob es das Debugging behindere: an der Stelle habe ich weitere andere Gesichstpunkte gebracht. Frank M. schrieb: > Wilhelm M. schrieb: >> was hieran wohl falsch sei:char c = getchar(); > > Willst Du so C-Programmierer vor ihrer eigenen Dummheit schützen Das wäre oft sehr gut ;-) > oder > was soll das? Schon im K&R steht drin, dass c vom Typ int sein muss. > > man getchar > > Da steht: > > int getchar(void); > > Einfacher gehts nicht. Konstruiere doch nicht irgendeinenen > Programmierer, der ein Blödmann ist. Ich will aber, dass der Compiler genau diesen Fehler erkennt und ablehnt. Das erreiche ich aber nicht, wenn ich irgendwelche DT hijacke. Mir ist klar, dass das historisch bedingt ist und einfach so ist, wie es ist. Trotzdem sollte jeder, der sich ernsthaft mit dem Programmieren beschäftigt mindestens einmal diese Schwachstelle erkennen. Und aus dieser Erkenntnis heraus ergibt sich vielleicht für den ein oder anderen der Wunsch, es besser zu machen. Wilhelm M. schrieb: > Ich will aber, dass der Compiler genau diesen Fehler erkennt und > ablehnt. Ach? Ein Ausschnitt aus Deinem Code:
Wie verhinderst Du, dass ich hier "char c = getchar()" hinschreibe? Du hast dieses von Dir konstruierte Problem nur in eine andere Ecke geschoben, mehr nicht. Das meinte ich mit rosa Mäntelchen.
Gast
#5430295
Wilhelm M. schrieb: > Und aus > dieser Erkenntnis heraus ergibt sich vielleicht für den ein oder anderen > der Wunsch, es besser zu machen. Das tust Du aber nicht. Du machst es unleserlicher. Das mag im Hobbybereich OK sein, wenn das Programm sowieso nur vom Autoren genutzt und gepflegt wird. Bei professionellem Arbeiten ist das Entscheidende die leichte Lesbarkeit für spätere Programmierer. Hier machst Du es nicht besser, sondern Dimensionen schlechter. Du schreibst Wegwerf-Software, und das ist nichts, was zur Nachahmung anregt. Frank M. schrieb: > Wilhelm M. schrieb: >> Ich will aber, dass der Compiler genau diesen Fehler erkennt und >> ablehnt. > > Ach? > Ein Ausschnitt aus Deinem Code: >
> > Wie verginderst Du, dass ich hier "char c = getchar()" hinschreibe? > > Du hast dieses Problem nur in eine andere Ecke geschoben, mehr nicht. Also nocheinmal: das was ich da geschrieben habe schuldet der Tatsache Rechnung, das ich das Beispiel auf einem Posix-System erstellt habe und ich grad keine Lust hatte, getchar() von scratch neu zu schreiben. Auch steht weiter oben schon, dass Du dies ruhig als Bestandteil einer alternativen Bibliothek vorstellen darfst. Insofern ist Dein Argument hinfällig. In der bare-metal Variante wird dann auch kein getchar() verwendet. Nop schrieb: > Wilhelm M. schrieb: >> Und aus >> dieser Erkenntnis heraus ergibt sich vielleicht für den ein oder anderen >> der Wunsch, es besser zu machen. > > Das tust Du aber nicht. Du machst es unleserlicher. Was ist denn unleserlicher daran? > Das mag im > Hobbybereich OK sein, wenn das Programm sowieso nur vom Autoren genutzt > und gepflegt wird. Mir scheint es eher daran zu liegen, dass die meisten sehr stark in einer starren C-Brille verhaftet sind. > Bei professionellem Arbeiten ist das Entscheidende > die leichte Lesbarkeit für spätere Programmierer. Hier machst Du es > nicht besser, sondern Dimensionen schlechter. Du schreibst > Wegwerf-Software, und das ist nichts, was zur Nachahmung anregt. Das letzte Beispiel von mir, was etwa in der Art war:
ist idiomatisches C++, insofern für Profis klar lesbar. Und zwar aus recht simplen Gründen: 1) es wird ein fertiger Algorithmus statt einer (hier Schleife) Eigenkonstruktion verwendet 2) es benutzt die wohlbekannte Iterator-Schnittstelle. Für reine "nur" C-Programmierer mag das ungewohnt sein.
Gast
#5430327
Wilhelm M. schrieb: > Was ist denn unleserlicher daran? Vergleich mal in Beitrag "Re: switch(Funktion()) möglich?" die Original-Variante mit dem Unfall, den Du daraus gebaut hast. Wenn Dir dabei tatsächlich nichts auffällt, dann dürfte es daran liegen, daß C++ an sich zu aufgeblasenem, unleserlichen Zeugs verführt. Eben genau der Grund, wieso Torvalds keine C++-Programmierer an Bord haben will. Du führst es exemplarisch vor. Und je mehr Du mit diesem Zeug hausieren gehst und in C-Threads herumtrollst, desto abschreckender wird es. Man kann das, was Du hier machst, echt nicht mehr anders als Trollen/Spammen bezeichnen. ES NERVT. Genauso wie die Zeugen Jehovas, die einen rausklingeln, obwohl man die nicht haben will. Nop schrieb: > Wilhelm M. schrieb: > >> Was ist denn unleserlicher daran? > > Vergleich mal in Beitrag "Re: switch(Funktion()) möglich?" > die Original-Variante mit dem Unfall, den Du daraus gebaut hast. Aus dem Original
was von einigen anderen als unsauber, schwer zu debuggen, etc. teilweise ohne Begründung abgelehnt wurde, und teilweise zu
mutierte, habe ich ein
gemacht. Also, was ist daran unleserlich? Die weitere Diskussion entstand dann um das Beispiel mit getchar()/putchar() von Frank. Und dort habe ich mir erlaubt, auf die Unzulänglichkeiten dieser historischen Schnittstelle hinzuweisen und auch Verbesserungen aufgezeigt. > Wenn Dir dabei tatsächlich nichts auffällt, dann dürfte es daran liegen, > daß C++ an sich zu aufgeblasenem, unleserlichen Zeugs verführt. Eben > genau der Grund, wieso Torvalds keine C++-Programmierer an Bord haben > will. Und nocheinmal die Frage: was ist an +
aufgeblasen. > Und je mehr Du mit diesem Zeug hausieren gehst und in C-Threads > herumtrollst, desto abschreckender wird es. Man kann das, was Du hier > machst, echt nicht mehr anders als Trollen/Spammen bezeichnen. > > ES NERVT. Genauso wie die Zeugen Jehovas, die einen rausklingeln, obwohl > man die nicht haben will. Der nach seinem EOD immer noch mitdiskutierende Moderator kann ja diesen Thread einfach schließen. Oder Du könntest Die Klingel hier abstellen. Warum machst Du das nicht?
Gast
#5430405
Wilhelm M. schrieb: > Also, was ist daran unleserlich? Der Rattenschwanz, den das danach noch nach sich zieht - im Verhältnis zu dem, was vorher dastand. Eine massive Verschlechterung, und das schon bei einer Trivialfunktion. > Der nach seinem EOD immer noch mitdiskutierende Moderator kann ja diesen > Thread einfach schließen. Oder Du könntest Die Klingel hier abstellen. > Warum machst Du das nicht? Ziemlich unverschämt. Du spammst wiederholt völlig offtopic rum und fragst dann auch noch, ob nicht irgendwer Dir den Stecker ziehen kann, indem der Thread dichtgemacht wird?! @Wilheim: Lasses, will doch eh keiner was von wissen. Schau dir lieber Boost.SML an. Das geht richtig gut auf AVR und sperrt Abstraktionsgenger wirkungsvoll aus. Ist besser investierte Zeit. Edit: seh gerade, ist eh schon auf deinem Radar. Wilhelm M. schrieb: >>> Ich erwarte also einen arithmetischen Umgang mit c. [...] >>> Bedeutung von EOF: end-of-file. Was hat dieser Sentinel-Wert >>> mit ganzzahliger Arithmetisch zu tun? >> Nichts. > Richtig. Und was hat das mit der verwendeten Programmiersprache zu tun? Nichts. >>> Was würde etwa (EOF + 42) bedeuten? >> >> Ist eine Zahl. Kann positiv oder negativ sein. >> Ist implementation-defined und entsprechend dokumentiert. > > Und deswegen sollte diese Operation auch nicht möglich sein > (s.a. Antwort auf die vorige Frage). Warum? Weil du der Meinung bist, das gehört so? Auf den Rest gehe ich nicht mehr ein, denn du hast den Unterschied zwischen "API" und "Programmiersprache" nicht verstanden. Carl D. schrieb: > @Wilheim: > Lasses, will doch eh keiner was von wissen. Danke für Dein Mitgefühl ;-) Ja, das Lager "alles ist ein int, andernfalls ist es ein C-String" ist schon eine harte Nuss. Habe gerade schon überlegt, ob ich den Wäschetrockner anschalten soll und dabei aus dem Haus gehen ... > Schau dir lieber Boost.SML an. Das geht richtig gut auf AVR und sperrt > Abstraktionsgenger wirkungsvoll aus. Ist besser investierte Zeit. > > Edit: seh gerade, ist eh schon auf deinem Radar. Ja, stimmt. Bin aber noch nicht so weit gekommen, und bin aber auch noch nicht so ganz überzeugt ... kann aber noch werden ;-) S. R. schrieb: > Wilhelm M. schrieb: >>>> Ich erwarte also einen arithmetischen Umgang mit c. [...] >>>> Bedeutung von EOF: end-of-file. Was hat dieser Sentinel-Wert >>>> mit ganzzahliger Arithmetisch zu tun? >>> Nichts. >> Richtig. > > Und was hat das mit der verwendeten Programmiersprache zu tun? > Nichts. Dann bist du wahrscheinlich auch der Meinung, dass
einen Wert in l von etwa 43.0 ergeben sollte? >>>> Was würde etwa (EOF + 42) bedeuten? >>> >>> Ist eine Zahl. Kann positiv oder negativ sein. >>> Ist implementation-defined und entsprechend dokumentiert. >> >> Und deswegen sollte diese Operation auch nicht möglich sein >> (s.a. Antwort auf die vorige Frage). > > Warum? Weil du der Meinung bist, das gehört so? Genau! Vielleicht hilft ja folgendes Beispiel zum Verständnis:
Die Addition zwischen int* (dem Typ von &a) und void* (dem Typ von NULL) bzw. allgemein zwischen Zeigertypen ist selbst in C nicht definiert. > Auf den Rest gehe ich nicht mehr ein, denn du hast den Unterschied > zwischen "API" und "Programmiersprache" nicht verstanden. Magst Du ihn mir erklären? Wilhelm M. schrieb: > Dann bist du wahrscheinlich auch der Meinung, dass > double distance1 = 42.0; // km? > double distance2 = 1.0; // mm? cm? who knows ... > double l = distance1 + distance2; > einen Wert in l von etwa 43.0 ergeben sollte? Ich bin der festen Überzeugung, dass 42.0 + 1.0 ziemlich genau gleich 43.0 ist, ja. Das gilt für Äpfel, Kilometer, Birnen und Meilen ebenso. Und wer Äpfel von Birnen nicht unterscheiden kann, hat sowieso ein anderes Problem. Wilhelm M. schrieb: >> Warum? Weil du der Meinung bist, das gehört so? > Genau! Gut, dann wäre das geklärt. Wilhelm M. schrieb: >> Auf den Rest gehe ich nicht mehr ein, denn du hast den Unterschied >> zwischen "API" und "Programmiersprache" nicht verstanden. > Magst Du ihn mir erklären? Nö.
Gast
#5431189
Wilhelm M. schrieb: > Was würde etwa (EOF + 42) bedeuten? EOF-42 wäre schlicht als der 43. Fehlercode zu interpretieren, wenn man weiß, daß EOF der erste ist, ob nun gerade definiert oder nicht. Das ist im Grunde eine brauchbare Darstellung. Ich habe das schon zu einem mygetchar() mit zusätzlichen Fehlercodes gewrapped verwendet. Ich verstehe nicht, was daran überhaupt so stört, daß hier eine Integer-Arithmetik nicht ausgeschlossen wird. Ok, im Fehlerfall, wenn das Result also als Fehlercode zu interpretieren ist, könnte man hier auf einen Aufzählungstyp (als member von union) eingrenzen oder wenn nur, wie gerade mal hier, nur ein einziger Fehlercode möglich ist, sogar auf Boolean. Wäre zumindest nur wenig nachteilig. Sehr dämlich wäre es allerdings für den Normalfall, wenn etwa ein ASCII-Code zurückgegeben wird. Was soll man damit ohne Integer-Arithmetik in der Praxis anfangen? Wie soll der Anwender ermitteln, ob es ein Steuerzeichen, Groß- oder Kleinbuchstabe ist? Wie macht er dann aus einem Klein- einen Großbuchstaben? Wie bekommt er den ASCII zu x, einer Zahl von 0-9? Selbst bei Pointern ist meist Arithmetik definiert, ob man sie nun braucht oder nicht. Ob ++p nun auf ein Objekt zeigt oder ins Nirwana, kann dir die Sprache auch nicht retten.
Gast
#5431199
Wilhelm M. schrieb: > Die Addition zwischen int* (dem Typ von &a) und void* (dem Typ von NULL) > bzw. allgemein zwischen Zeigertypen ist selbst in C nicht definiert. Der wesentliche Unterschied: hierbei hat man nicht einen Haufen sinnlosen Overengineerings betrieben, eigens um die Addition unmöglich zu machen. Sondern da diese Addition sowieso nichts Sinnvolles täte, hat man sie halt nicht implementiert. KISS. batman schrieb: > Wilhelm M. schrieb: >> Was würde etwa (EOF + 42) bedeuten? > > EOF-42 wäre schlicht als der 43. Fehlercode zu interpretieren, wenn man > weiß, daß EOF der erste ist, ob nun gerade definiert oder nicht. Das ist > im Grunde eine brauchbare Darstellung. Abgesehen davon, dass oben (EOF + 42) stand (was ja auch positiv sein kann und damit ein Ascii-Code darstellen kann): was soll denn wohl der 43. Fehlercode (EOF - 42) bedeuten im Kontext von getchar()? Da der Wert von EOF implementierungsabhängig ist ... > Ich habe das schon zu einem > mygetchar() mit zusätzlichen Fehlercodes gewrapped verwendet. Ich > verstehe nicht, was daran überhaupt so stört, daß hier eine > Integer-Arithmetik nicht ausgeschlossen wird. Was soll denn (FehlerCode1 * FehlerCode2) bedeuten? Das ist schlicht sinnlos. Genauso sinnlos wie zwei Zeigerwerte zu multiplizieren. Und dies erlaubt die Sprache C auch sinnvollerweise nicht (s.u.). Da man in C aber keine Datentypen im engeren Sinn definieren kann, bleibt einem hier als eine Möglichkeit, eine primitiven Datentyp zu zweckentfremden. Und das schafft massiv Nachteile. > Sehr dämlich wäre es allerdings für den Normalfall, wenn etwa ein > ASCII-Code zurückgegeben wird. Was soll man damit ohne > Integer-Arithmetik in der Praxis anfangen? Zu Zeichenketten zusammenfügen, vergleichen, in Großbuchstaben umwandeln, anordnen, ... > Wie soll der Anwender > ermitteln, ob es ein Steuerzeichen, Groß- oder Kleinbuchstabe ist? bool isLower(AsciiChar); > Wie > macht er dann aus einem Klein- einen Großbuchstaben? AsciiChar toUpper(AsciiChar); > Wie bekommt er den > ASCII zu x, einer Zahl von 0-9? AsciiChar x = ...; static_cast<uint8_t>(x); uint8_t v = x.toInt(); uint8_t w = toInt(x); > Selbst bei Pointern ist meist Arithmetik definiert, ob man sie nun > braucht oder nicht. Aber nur Addition und Subtraktion, keine Multiplikation, Division... Nop schrieb: > Wilhelm M. schrieb: > >> Die Addition zwischen int* (dem Typ von &a) und void* (dem Typ von NULL) >> bzw. allgemein zwischen Zeigertypen ist selbst in C nicht definiert. > > Der wesentliche Unterschied: hierbei hat man nicht einen Haufen > sinnlosen Overengineerings betrieben, eigens um die Addition unmöglich > zu machen. Sondern da diese Addition sowieso nichts Sinnvolles täte, hat > man sie halt nicht implementiert. KISS. Sehr interessant! Und da die Multiplikation zweier Fehlercodes auch sinnlos ist, definiert man sie eben nicht. Sehr gut erkannt ;-)
Gast
#5431317
Wilhelm M. schrieb: > Und da die Multiplikation zweier Fehlercodes auch sinnlos ist, definiert > man sie eben nicht. Muß man auch nicht, sie funktioniert trotzdem. Auch wenn sie dann nichts Sinnvolles tut. Was Du willst, ist eben nicht, sie nicht zu definieren, sondern Umwege zu gehen, damit sie undefiniert WIRD. Und das ist überkompliziertes Denken von Leuten, die im Grunde unterbeschäftigt sind und leer laufen. Daher diese krampfigen Versuche, absurde, realitätsferne Fehlerszenarien zu "verhindern" - und dafür auch gerne unlesbaren Wegwerfcode zu produzieren. Sieh Dir mal den Code von Stockfish an, der wahrscheinlich weltbesten Schach-Engine. Auch C++, aber gut lesbar, weil nicht auf Krampf möglichst viele C++-Features reingeklatscht wurden. Und nur 5% langsamer als der C-Port. Nop schrieb: > Wilhelm M. schrieb: > >> Und da die Multiplikation zweier Fehlercodes auch sinnlos ist, definiert >> man sie eben nicht. > > Muß man auch nicht, sie funktioniert trotzdem. Auch wenn sie dann nichts > Sinnvolles tut. Naja, wie Du jetzt richtig erkannt hast, tut diese Operation nichts sinnvolles. Und dann sollte sie auch nicht möglich sein. Deswegen definiere ich sie nicht. Ist doch eigentlich ganz einfach. Wenn Du in Deinem Code gerne Operationen drin hast, die nichts Sinnvolles tun, dann ist das Deine Entscheidung. Für mich ist das aber wiederum nicht sinnvoll.
Gast
#5431449
Wilhelm M. schrieb: > Was soll denn (FehlerCode1 * FehlerCode2) bedeuten? Das ist schlicht > sinnlos. Genauso sinnlos, wie zwei Geldbeträge zu multiplizieren, zwei Temperaturen, Spannungen... Wer will denn für alles und jedes eine eigene extra (beschränkte) Arithemtik definieren oder einbinden. Die Fehler macht man dann eh woanders, weil die Zeit knapp wird. Wilhelm M. schrieb: >> Sehr dämlich wäre es allerdings für den Normalfall, wenn etwa ein >> ASCII-Code zurückgegeben wird. Was soll man damit ohne >> Integer-Arithmetik in der Praxis anfangen? > > Zu Zeichenketten zusammenfügen, vergleichen, in Großbuchstaben > umwandeln, anordnen, ... Und das macht eine Integer-Arithmetik - auch wenn du sie hinter zusätzlichen Wrappern versteckst. batman schrieb: > Wilhelm M. schrieb: >> Was soll denn (FehlerCode1 * FehlerCode2) bedeuten? Das ist schlicht >> sinnlos. > > Genauso sinnlos, wie zwei Geldbeträge zu multiplizieren, zwei > Temperaturen, Spannungen... > > Wer will denn für alles und jedes eine eigene extra (beschränkte) > Arithemtik definieren oder einbinden. Die Fehler macht man dann eh > woanders, weil die Zeit knapp wird. https://en.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_of_failure 125 fucking million reasons Vincent H. schrieb: > batman schrieb: >> Wilhelm M. schrieb: >>> Was soll denn (FehlerCode1 * FehlerCode2) bedeuten? Das ist schlicht >>> sinnlos. >> >> Genauso sinnlos, wie zwei Geldbeträge zu multiplizieren, zwei >> Temperaturen, Spannungen... >> >> Wer will denn für alles und jedes eine eigene extra (beschränkte) >> Arithemtik definieren oder einbinden. Die Fehler macht man dann eh >> woanders, weil die Zeit knapp wird. > > https://en.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_of_failure > > 125 fucking million reasons Danke Vincent. Den Hinweis hatte ich mir die ganze Zeit verkniffen, denn weiter oben wurde ja schon behauptet, dass man solche Fehler durch Sprüche an der Wand o.d.gl., Projektmanagement, etc. verhindert kann.
Gast
#5431466
Vincent H. schrieb: > https://en.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_of_failure > > 125 fucking million reasons Nö, da gehts um die falsche Einheit fürs Gewicht, der Wert in Pfund statt Kilo. Die Arithmetik wäre dieselbe und durch blindes Vertrauen in die Entwicklungsumgebung und mangelndes Mitdenken entstehen genau solche Fehler. Da steht jetzt nicht, ob das Programm in C oder C++ geschrieben war, ist auch Wurscht. batman schrieb: > Vincent H. schrieb: >> https://en.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_of_failure >> >> 125 fucking million reasons > > Nö, da gehts um die falsche Einheit fürs Gewicht, der Wert in Pfund > statt Kilo. Weiter oben hatte ich das Beispiel schon mal gebracht mit Entfernungen. Hast Du schon mal in einer Sprache programmiert, in der man sich DT selbst definieren kann? > Die Arithmetik wäre dieselbe und durch blindes Vertrauen in > die Entwicklungsumgebung und mangelndes Mitdenken entstehen genau solche > Fehler. Mit Ausnahme der Skalierungs- bzw. Umrechnungsfaktoren ;-) Und weil solche Fehler entstehen und tatsächlich gemacht werden, ist es wichtig, die Schnittstelle so wasserdicht wie möglich zu machen: Eine Schnittstelle sollte leicht richtig und schwer falsch zu benutzen sein. Wenn aber alles ein double ist ohne Semantik, dann kommen eben solche Fehler vor. >The discrepancy between calculated and measured position, resulting in the
discrepancy between desired and actual orbit insertion altitude, had been noticed
earlier by at least two navigators, whose concerns were dismissed.
Wie aus einem Comic.
"Die Rechnung kommt nicht hin..."
"Ach... Das passt schon!"
Heiko L. schrieb: >>The discrepancy between calculated and measured position, resulting in the > discrepancy between desired and actual orbit insertion altitude, had been noticed > earlier by at least two navigators, whose concerns were dismissed. > > Wie aus einem Comic. > "Die Rechnung kommt nicht hin..." > "Ach... Das passt schon!" Ja, so wie in diesem Thread gerade ... ;-) Wilhelm M. schrieb: > Mit Ausnahme der Skalierungs- bzw. Umrechnungsfaktoren ;-) > > Und weil solche Fehler entstehen und tatsächlich gemacht werden, ist es > wichtig, die Schnittstelle so wasserdicht wie möglich zu machen: > > Eine Schnittstelle sollte leicht richtig und schwer falsch zu benutzen > sein. > > Wenn aber alles ein double ist ohne Semantik, dann kommen eben solche > Fehler vor. Naja, eigentlich war es ja abgesprochen, dass dort alles in SI units übergeben wird. Wenn man da eine Funktion hat, deren Spec sagt "returns [value] in meters", es kommen aber feet raus oder sowas, dann ist da etwas falsch gelaufen. Da macht es dann auch keinen Unterschied, ob das ein falsch typisierter Wert ist oder nicht...
Gast
#5431495
Wilhelm M. schrieb: >> Die Arithmetik wäre dieselbe und durch blindes Vertrauen in >> die Entwicklungsumgebung und mangelndes Mitdenken entstehen genau solche >> Fehler. > > Mit Ausnahme der Skalierungs- bzw. Umrechnungsfaktoren ;-) Die nun immerhin in deiner Fantasie existieren, weil du im Nachhinein den Fehler erkannt hast. Das hilft nur leider bei der Entwicklung nix, wie man sieht. Heiko L. schrieb: > Naja, eigentlich war es ja abgesprochen, dass dort alles in SI units > übergeben wird. Wenn man da eine Funktion hat, deren Spec sagt "returns > [value] in meters", es kommen aber feet raus oder sowas, dann ist da > etwas falsch gelaufen. Da macht es dann auch keinen Unterschied, ob das > ein falsch typisierter Wert ist oder nicht... Das schöne ist ja: wenn dort der DT Feet herauskommt, kann ich den ja auch ggf. korrekt(!) durch Kilogramm dividieren. Es ist eigentlich gaaanz einfach. Wilhelm M. schrieb: > Das schöne ist ja: wenn dort der DT Feet herauskommt, kann ich den ja > auch ggf. korrekt(!) durch Kilogramm dividieren. Es ist eigentlich > gaaanz einfach. Nicht, wenn sein Betrag Meter sind. Heiko L. schrieb: > Wilhelm M. schrieb: >> Das schöne ist ja: wenn dort der DT Feet herauskommt, kann ich den ja >> auch ggf. korrekt(!) durch Kilogramm dividieren. Es ist eigentlich >> gaaanz einfach. > > Nicht, wenn sein Betrag Meter sind. Nochmal:
Jetzt ist es egal, ob der DT von d nun Meter oder Feet ist. Es gibt dann zwei Möglichkeiten: a) die Division zwischen Feet und Second ist nicht definirt. Das Programm kompiliert nicht. b) die Division ist definiert und berücksichtigt gleich den Umrechnungsfaktor. Das Ergebnis ist in jedem Fall Velocity in der Einheit [m/s]. Du kennst den Unterschied zwischen Einheit und Betrag doch. Wenn man statt 5m 5ft schreibt, ist es falsch. Das geht auch mit Length<feet>(5) oder ähnlichem. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|