Possetitjel schrieb:> Frage am Rande: Aufgrund welcher Verschwörung fehlt> Tcl regelmäßig in solchen Aufzählungen?
Weil das keine besonders verbreitete Sprache ist, und funktionale
Programmierung nur ein Teilaspekt ist, im Gegensatz zu z.B. Haskell? In
C++ kann man auch funktional programmieren, insbesondere das
template-System ist quasi funktionale Programmierung.
Gerhard O. schrieb:> Ich habe mir das Wiki dazu durchgelesen. Leider verstehe ich von der> Unterliegenden Mathe zum Teil nur Bahnhof. Das ist mir zu theoretisch.
Lamdakalkül für Doofies: "Funktionen können Funktionen als Parameter
haben."
Und schon hast du die funktionale Programmierung verstanden.
Dr. Sommer schrieb:> char* greeting (const char* firstName, size_t firstNameLength, const> char* lastName, size_t lastNameLength, ) {> const char a [] = "Hallo, ";> char* res = malloc (sizeof (a) + firstNameLength + lastNameLength +> 2);> if (!res) return NULL;> memcpy (res, a, sizeof (a));> memcpy (res+sizeof (a), firstName, firstNameLength);> res [sizeof (a)+firstNameLength] = ' ';> memcpy (res+sizeof (a)+firstNameLength+1, lastName, lastNameLength);> res [sizeof (a)+firstNameLength+lastNameLength+1] = ' ';> return res;> }
Ich kenne keinen C-Programmierer, der so was schreiben würde. Auch die
Erfinder der String-Library haben sich dabei was gedacht.
Die Entsprechung zum C++-Beispiel sieht eher so aus:
Markus F. schrieb:> Die Entsprechung zum C++-Beispiel sieht eher so aus:
Funktioniert nicht mit Strings die 0-Bytes enthalten. Zugegeben, das ist
bei Real-Namen nicht besonders sinnvoll, aber es gibt oft Situationen wo
man das braucht. Besonders effizient ist das ständige Iterieren mittels
strlen auch nicht.
Dr. Sommer schrieb:> Possetitjel schrieb:>> Ich habe überhaupt nichts gegen höhere Abstraktion, wenn>> zuvor die einfachen, leicht zugänglichen Modelle und>> Vorstellungen erklärt würden.>> Ich finde OOP sehr intuitiv und verständlich.
OOP ist für mich ein einfaches und sehr sinnvolles Konzept,
das typischerweise auf eine für mich absolut unverständliche
Art erklärt wird.
Ich habe sie nur durch konsequentes Umdeuten aller Begriffe
in Kategorien der Automatentheorie verstanden, und ich werde
immer noch hippelig, wenn ich Auslassungen echter Informatiker
über OOP lesen muss. Ich kann den Frust darüber, wie man eine
einfache und sinnvolle Sache dermaßen frachtbriefmäßig
umständlich erklären kann, nur schlecht unterdrücken.
> Kurioserweise haben meistens die E-Techniker Probleme damit,> obwohl da eigentlich noch mehr in Komponenten und Black-Boxes> gedacht wird (IC's, Platinen, Baugruppen, ...).
Das ist sehr interessant, dass Du das sagst, weil ich mich in
meiner Vermutung bestätigt sehe, dass es nicht das Konzept
an sich ist, das die E-Techniker abstößt, sondern die Art und
Weise der Darstellung.
Es könnte sein, dass Wilhelm auf eine Art Recht hat, die ich
vorhin nicht gesehen habe: Möglicherweise erwerben Informatiker
trotz der Überbetonung von Sprachen und Grammatiken genügend
Wissen über Automatentheorie, so dass sich für sie die Konzepte
der OOP quasi nebenbei durch genaues Hinsehen erschließen.
E-Techniker haben diese Kenntnisse der Automatentheorie nicht
zwingenderweise; also entsteht da erstmal eine Blockade. Es
ist aber, um einigermaßen Programmieren zu können, gar nicht
notwendig, die Initiation durch TheoInf I + II über sich
ergehen zu lassen -- es genügt, den deutlich kleineren Teil
des Feldes zu beherrschen, der sich mit (endlichen) Automaten
befasst. Das wiederum sehen die Informatiker nicht, weil ihnen
mangels Notwendigkeit nicht bewusst ist, dass man Automaten-
theorie auch betreiben kann, ohne sich um die Korrespondenzen
zu den Grammatiken zu scheren.
Dr. Sommer schrieb:> Possetitjel schrieb:>> Frage am Rande: Aufgrund welcher Verschwörung fehlt>> Tcl regelmäßig in solchen Aufzählungen?>> Weil das keine besonders verbreitete Sprache ist, und> funktionale Programmierung nur ein Teilaspekt ist, im> Gegensatz zu z.B. Haskell?
Okay, das gibt Sinn. Danke.
Possetitjel schrieb:> es genügt, den deutlich kleineren Teil des Feldes zu beherrschen, der> sich mit (endlichen) Automaten befasst.
Endliche Automaten reichen da nicht, es muss mindestens bis zur Turing
Maschine gehen damit übliche Programme abbildbar werden. Und dafür
brauchts dann doch ein Semester.
Possetitjel schrieb:> dass man Automaten- theorie auch betreiben kann, ohne sich um die> Korrespondenzen zu den Grammatiken zu scheren.
Da das aber die Hauptanwendung ist gehört es irgendwie dazu.
In Anbetracht der Tatsache dass die meisten Informatiker TheoInf
überhaupt nicht verstehen aber gewöhnliches OOP mit Kapselung und
Datenstrukturen schon, würde ich nicht sagen dass es besonders hilfreich
wäre Automaten als Grundlage für alles darzustellen. Eine String Klasse
ist als Text intuitiver verstanden denn als Turing Maschine, wo auf dem
Band Zeichen, Länge usw liegen. Schlimmer wird es z.B. bei Listen oder
Graphen. Komplexe OOP-Strukturen sind da noch viel weiter entfernt...
Possetitjel schrieb:> OOP ist für mich ein einfaches und sehr sinnvolles Konzept, das> typischerweise auf eine für mich absolut unverständliche Art erklärt> wird.
Für dich mag das zutreffen, aber ich glaube nicht dass das für die
Mehrheit gilt. Das Konzept der Datenkapselung dürfte vielen besser
liegen. Insbesondere weil die meisten Informatiker Begriffe wie
Schaltwerk, Kombinatorik (in dem Zusammenhang), und 74er nie gehört
haben.
Markus F. schrieb:> Dr. Sommer schrieb:> ... Strings die 0-Bytes enthalten...>> das ist für C-Programmierer ein Oxymoron.
Dann halt Byte-Array. In den meisten Sprachen muss man sich um solche
Probleme halt keine Sorgen machen...
PS: Ich würde im Studium eher noch mehr auf die Details der
Programmiersprachen eingehen, und dafür Dinge wie Jura oder BWL
reduzieren. Wenn ich sehe was so am Code produziert wird (insbesondere
in C und C++) überkommt einen das Gruseln. In C sind viele Dinge einfach
falsch und werden trotzdem wie selbstverständlich überall so gemacht...
Hallo,
Dr. Sommer schrieb:> PS: Ich würde im Studium eher noch mehr auf die Details der> Programmiersprachen eingehen...
Was meinst du mit "Details"?
rhf
Possetitjel schrieb:> Es könnte sein, dass Wilhelm auf eine Art Recht hat, die ich> vorhin nicht gesehen habe: Möglicherweise erwerben Informatiker> trotz der Überbetonung von Sprachen und Grammatiken genügend> Wissen über Automatentheorie, so dass sich für sie die Konzepte> der OOP quasi nebenbei durch genaues Hinsehen erschließen.
Das ist komplett daneben. Ich habe fast zehn Jahre vor dem Studium mit
dem Programmieren angefangen, direkt mit C# und OOP. Gerade Java und C#
erzwingen OOP ja extrem. Da hatte ich keine Ahnung von Automatentheorie
oder Ähnliches. Und trotzdem haben sich mir diese Konzepte erschlossen.
Und ich war da nicht der Einzige, ein paar Jungs aus der Computer-AG
haben das auch verstanden. Es ist einfach nicht nötig. Das Buch, dass
ich damals verwendete, nutze die Analogie eines Autos oder eines
Bauernhofes, bin mir nicht mehr so sicher. Auf jeden Fall so, dass es
ein 0815 Mensch ohne jegliche Vorkenntnisse verstehen kann. Andererseits
ist es im Studium auch so, dass viele im ersten Semester direkt mit Java
anfangen, Theoretische Informatik kommt hingegen erst später.
Possetitjel schrieb:> Ich habe sie nur durch konsequentes Umdeuten aller Begriffe> in Kategorien der Automatentheorie verstanden, und ich werde> immer noch hippelig, wenn ich Auslassungen echter Informatiker> über OOP lesen muss. Ich kann den Frust darüber, wie man eine> einfache und sinnvolle Sache dermaßen frachtbriefmäßig> umständlich erklären kann, nur schlecht unterdrücken.
Genau das ist eben dein Problem, Umdeuten ist halt nicht Verstehen. Du
bist von der Automathentheorie zu sehr vereinnahmt, weshalb du den
Sachverhalt nicht mehr anders betrachten kannst. Die Betrachtungsweise
musst du fallen lassen. Deswegen auch die Abneigung gegenüber der
Vererbung, die aber ein essentieller Teil von OOP ist, weil sie mit
"deiner Betrachtungsweise" nicht harmoniert.
Niklas Gürtler schrieb:> Possetitjel schrieb:>> es genügt, den deutlich kleineren Teil des Feldes zu>> beherrschen, der sich mit (endlichen) Automaten befasst.>> Endliche Automaten reichen da nicht, es muss mindestens> bis zur Turing Maschine gehen damit übliche Programme> abbildbar werden.
Es ging um die Frage, warum viele E-Techniker mit OOP
solche Probleme haben.
Um die Grundidee der OOP zu erklären, muss ich nicht
bis zur Turingmaschine gehen -- das habe ich nämlich
in meinem ersten, überlangen Beitrag schon getan.
> Possetitjel schrieb:>> dass man Automatentheorie auch betreiben kann, ohne>> sich um die Korrespondenzen zu den Grammatiken zu>> scheren.>> Da das aber die Hauptanwendung ist gehört es irgendwie> dazu.
Kein Zweifel: Hier spricht ein Informatiker.
Für mich liegt die Domäne der Automatentheorie in allen
Arten von Prozess- und Ablaufsteuerungen. Die Korrespondenz
zu den Grammatiken ist für mich ein winziges Spezialthema,
das nur für die theoretischen Informatiker wichtig ist.
Ich schreibe das nicht als Provokation, sondern weil es
die Wahrheit ist.
Ich hatte eine kleine Weile Berührung mit Steuerungs-
programmierung (SPS), und ich wäre völlig erschossen gewesen,
wenn ich nichts von endlichen Automaten gewusst hätte.
> In Anbetracht der Tatsache dass die meisten Informatiker> TheoInf überhaupt nicht verstehen aber gewöhnliches OOP> mit Kapselung und Datenstrukturen schon, würde ich nicht> sagen dass es besonders hilfreich wäre Automaten als> Grundlage für alles darzustellen.
Das beweist erstmal nur, dass die Art und Weise der
Darstellung von TheoInf schlecht ist.
> Eine String Klasse ist als Text intuitiver verstanden> denn als Turing Maschine, wo auf dem Band Zeichen, Länge> usw liegen.
Wenn ich "Automatentheorie" sage, dann denke ich primär
an ENDLICHE Automaten.
> Possetitjel schrieb:>> OOP ist für mich ein einfaches und sehr sinnvolles Konzept,>> das typischerweise auf eine für mich absolut unverständliche>> Art erklärt wird.>> Für dich mag das zutreffen, aber ich glaube nicht dass das> für die Mehrheit gilt. Das Konzept der Datenkapselung dürfte> vielen besser liegen.
Ein "Objekt" IST ein (häufig endlicher) Automat.
> Insbesondere weil die meisten Informatiker Begriffe wie> Schaltwerk, Kombinatorik (in dem Zusammenhang), und 74er> nie gehört haben.
Das ist ja der Skandal!
Mist... überlesen:
Dr. Sommer schrieb:> Possetitjel schrieb:>> Die praktische oder angewandte Informatik IST für mich>> eine Ingenieursdisziplin, genauso wie die Elektrotechnik.>> Für andere aber nicht. Ich merke deutlich die Unterschiede> im Denken bei der Zusammenarbeit mit Ingenieuren.
Nur interessehalber: Welche sind das? Bzw. wie zeigen sie
sich?
Possetitjel schrieb:> Carl D. schrieb:>>> Manchmal kann der Erkenntnisstand der "Pioniere" aber>> nicht auf Nachzügler warten.>> Es geht nicht um den Erkenntnisstand an sich, sondern> um die Unfähigkeit oder die Unlust, die unter vielen> persönlichen Mühen gewonnenen Erkenntnisse so umzuformu-> lieren, dass sie für andere leicht verständlich werden.>> Edison sage, Genie sei 1% Inspiration und 99% Transpiration.>> Die geniale Erkenntnis zu haben ist 1%, sie verständlich> zu formulieren und lehrbar zu machen, die restlichen 99%.
Aha, und worin leitet sich der Anspruch derer ab, die sich gedanklich
auf das Vorgestellte nicht selber einlassen wollen, die Erkenntnisse
mundgerecht vorgelegt zu bekommen?
@Possetitjel:
Ich habe mir die Mühe gemacht, deinen ellenlangen Beitrag von oben
durchzulesen, jetzt musst du dasselbe auch mit meinem tun ;-)
Alle anderen dürfen ihn gerne überspringen.
Wenn ich dich richtig verstehe, versucht du, sämtliche Eigenschaften von
Programmiersprachen auf Automaten abzubilden, um sie dadurch besser zu
verstehen. Kann es sein, dass du dich damit selber blockierst und so
somit genau das Gegenteil von dem erreichst, was du eigentlich
anstrebst?
Was du in deinen Beispielen mittels Automaten beschreibst, sind im
Wesentlichen Ablaufstrukturen (Sprünge, Unterprogrammaufrufe, Objekte
mit Memberfunktionen, Parallelität usw.). Im Gegensatz zu Assembler und
Ur-Fortran zeichnen sich moderne Sprachen aber durch weit mehr als nur
die von ihnen unterstützten Ablaufstrukturen aus, als da wären:
- Datentypen (numerisch, textuell, primitiv, zusammengesetzt, ...)
- Typsysteme (stark, schwach, statisch, dynamisch, flach, hierarchisch,
...)
- Möglichkeiten der Metaprogrammierung (Lisp-Makros, C++-Templates, ...)
- u.v.m.
Ich bin zwar Informatiker, beschäftige mich aber auch mit Elektronik und
sonstiger Technik. Deswegen versuche auch ich, meinem Verständnis
abstrakter Sachverhalte dadurch auf die Sprünge zu helfen, dass ich in
meiner Vorstellung kleine Maschinchen baue, die mit irgendetwas (wie
bspw. Daten, Programmcode, geometrische Objekte oder was auch immer)
gefüttert werden und daraus – entweder einmalig oder laufend wie am
Fließband – unter heftiger (vorgestellter) Geräuschentwicklung
irgendetwas anderes erzeugen.
Das funktioniert für viele Dinge (wie bspw. eine Programmschleife, einen
Stack und sogar die Synchronisation zwischen mehreren Prozessen) ganz
hervorragend, aber bei den in der obigen Aufzählung genannten Punkten
ist meine Phantasie nicht mehr in der Lage, solche Maschinchen zu
konstruieren. Für einige Dinge (wie bspw. Mehrfachrekursion) kann ich
zwar ein entsprechendes Maschinchen bauen, aber bei der Inbetriebnahme
verklemmt es sich oder zerfällt sogar in seine Einzelteile, weil meine
Vorstellungskraft für das Durchspielen der Bewegungsabläufe nicht
ausreicht.
Ich habe deswegen lange nach einem besseren Ersatz für diese Maschinchen
gesucht und schließlich auch gefunden:
Mathematische Modelle
Diejenigen, die schon lange vor mir auf diese Idee kamen, habe ich
früher immer als unverbesserliche Theoretiker angesehen und ihre
unverständlichen Aussagen als Geschwurbel abgetan.
Der Punkt bei der Sache: Ich musste anhand einiger konkreter Probleme
erst einmal selber auf den Dreh kommen, um zu glauben, dass da etwas
dran ist. Danach hat plötzlich auch das Geschwurbel der anderen (naja,
vieler, nicht aller ;-)) für mich eine Bedeutung bekommen.
Endgültig die Augen aufgegangen sind mir, als ich begann, mich mit
funktionaler Programmierung zu beschäftigen. In der reinen FP gibt es
weder Abläufe noch Zustände, weswegen die Vorstellung von Maschinchen
schon per se zu nichts führen kann.
Mit mathematische Modellen hingegen kann man einige Dinge tun, die mit
den Maschinchen in meinem Kopf kaum möglich sind:
- Man kann sie leicht zu Papier bringen und damit komplizierte
Gedankengänge auch außerhalb des Kopfs speichern.
- Man kann damit Beweise führen und sich so selber klar machen, das ein
komplizierter Algorithmus, den man gerade geschrieben hat, auch
wirklich in allen Kontexten das richtige Ergebnis liefert.
- Man kann sie transformieren. Eine praktische Anwendung davon ist es,
Programmcode so umzuschreiben, dass er effizienter wird, ohne dabei
Fehler einzubauen. Die Vorgehensweise ist letztendlich nichts anderes
als geschickte Umformen mathematischer Terme. Konkrete Beispiele
finden sich bspw. in dem Buch "Pearls of Functional Algorithm Design"
von Richard Bird.
Immer wieder fallen mir bei schwierigen Problemen weitere Wege ein, die
zwar abstrakt anmuten, aber letztendlich dazu geeignet sind, hinderliche
Knoten in Gehirnwindungen zu lösen und damit die Problemstellung zu
vereinfachen.
Und das Beste dabei: Die Erkenntnisse, die man dabei gewinnt, lassen
sich nicht nur auf die FP, sondern mit leichten Einschränkungen auch auf
die klassische Programmierung in C oder C++ anwenden.
Was ich damit ausdrücken möchte: Die Informatiker, deren Geschwurbel du
nicht verstehst, sind entweder tatsächlich Dummschwätzer oder Angeber,
oder aber sie denken in Modellen, die sie persönlich zwar befähigen,
selbst schwierigste Probleme zu lösen, die sich aber leider nicht in
deine Welt der Automaten übersetzen lassen. Umgekehrt haben diese Leute
vielleicht (wenn sie sich nie damit beschäftigt haben) Schwierigkeiten
damit, sich ein zeitlich veränderliches Signal im Frequenzbereich
vorzustellen, was für einen Elektroingenieur nichts besonders ist.
Carl D. schrieb:> Possetitjel schrieb:>> Carl D. schrieb:>>>>> Manchmal kann der Erkenntnisstand der "Pioniere" aber>>> nicht auf Nachzügler warten.>>>> Es geht nicht um den Erkenntnisstand an sich, sondern>> um die Unfähigkeit oder die Unlust, die unter vielen>> persönlichen Mühen gewonnenen Erkenntnisse so umzuformu->> lieren, dass sie für andere leicht verständlich werden.>>>> Edison sage, Genie sei 1% Inspiration und 99% Transpiration.>>>> Die geniale Erkenntnis zu haben ist 1%, sie verständlich>> zu formulieren und lehrbar zu machen, die restlichen 99%.>> Aha, und worin leitet sich der Anspruch derer ab, die sich> gedanklich auf das Vorgestellte nicht selber einlassen> wollen, die Erkenntnisse mundgerecht vorgelegt zu bekommen?
Auch wenn das wenig bis nichts mit Wilhelm zu tun hat:
Der Anspruch leitet sich schlicht aus der normativen Kraft
des Faktischen ab: Wenn ich die Wahl zwischen einem
unverständlichen und einem klar verständlichen Buch habe,
dann wähle ich ganz sicher nicht das unverständliche. Eins
meiner wenigen Privilegien besteht darin, mir meine Lehrer
aussuchen zu können.
Es interessiert mich keinen Deut, wenn der Autor des ersten
ein verkanntes Genie, der Autor des zweiten Buches aber nur
gutes Mittelmaß ist.
Wer sich zu fein ist, Arbeit in verständliche Darstellung zu
stecken, der bleibt am Ende eben auch genau das: Unverstanden.
Das ist sein Problem, nicht meins.
Possetitjel schrieb:> Carl D. schrieb:>>> Possetitjel schrieb:>>> Carl D. schrieb:>>>>>>> Manchmal kann der Erkenntnisstand der "Pioniere" aber>>>> nicht auf Nachzügler warten.>>>>>> Es geht nicht um den Erkenntnisstand an sich, sondern>>> um die Unfähigkeit oder die Unlust, die unter vielen>>> persönlichen Mühen gewonnenen Erkenntnisse so umzuformu->>> lieren, dass sie für andere leicht verständlich werden.>>>>>> Edison sage, Genie sei 1% Inspiration und 99% Transpiration.>>>>>> Die geniale Erkenntnis zu haben ist 1%, sie verständlich>>> zu formulieren und lehrbar zu machen, die restlichen 99%.>>>> Aha, und worin leitet sich der Anspruch derer ab, die sich>> gedanklich auf das Vorgestellte nicht selber einlassen>> wollen, die Erkenntnisse mundgerecht vorgelegt zu bekommen?>> Auch wenn das wenig bis nichts mit Wilhelm zu tun hat:>> Der Anspruch leitet sich schlicht aus der normativen Kraft> des Faktischen ab: Wenn ich die Wahl zwischen einem> unverständlichen und einem klar verständlichen Buch habe,> dann wähle ich ganz sicher nicht das unverständliche. Eins> meiner wenigen Privilegien besteht darin, mir meine Lehrer> aussuchen zu können.>> Es interessiert mich keinen Deut, wenn der Autor des ersten> ein verkanntes Genie, der Autor des zweiten Buches aber nur> gutes Mittelmaß ist.
Warum liest und kommentierst du dann das erste Buch?
> Wer sich zu fein ist, Arbeit in verständliche Darstellung zu> stecken, der bleibt am Ende eben auch genau das: Unverstanden.
Richtig, von manchen unverstanden.
Und nochmal, es gibt keinen Anspruch auf Erkenntnis und schon gar nicht
in der Passivform.
> Das ist sein Problem, nicht meins.
Dann Versuch doch nicht, ihm das wegzunehmen.
Yalu X. schrieb:>> Ich habe mir die Mühe gemacht, [.]einen ellenlangen Beitrag von oben> durchzulesen ..>> Alle anderen dürfen ihn gerne überspringen.
Falls es dich interessiert, ich habe bei dir nicht das Gefühl "irgendein
Geschwurbel" zu lesen im Gegensatz zu manch anderen Texten hier, die mir
reichlich wirr und ohne erkennbaren Faden erscheinen. Ich frage mich nur
gerade angesichts vieler alltäglicher Programmieraufgaben, welche
speziellen Applikationen es denn überhaupt notwendig machen den Pfad des
"normalen", intuitiven Lösungsansatzes zu verlassen, um sich einer
völlig anderen Herangehensweise bedienen zu müssen?
Ach ja ;) schrieb:> Ich frage mich nur> gerade angesichts vieler alltäglicher Programmieraufgaben, welche> speziellen Applikationen es denn überhaupt notwendig machen den Pfad des> "normalen", intuitiven Lösungsansatzes zu verlassen, um sich einer> völlig anderen Herangehensweise bedienen zu müssen?
Jetzt wage ich mich nochmals aufs Eis:
Ich stelle mir vor, daß im herkömmlichen Feld der Hardware intensiven
Steueraufgaben traditionelle Methoden immer noch sinnreich und
vernünftig sind weil man tonnenweise eine wiederverwendbare, verläßliche
und bewährte Codebasis hat.
Es sind eher die modernen Applikation wie IoT, Internet verbundener
Sachen die sehr Daten intensiv und von Protokollen abhängig sind und
viel kommunizieren wo die neuen Werkzeuge dem Designer das Leben
leichter machen. Es gibt ja heute so viele Aufgaben die aus 90% GUI und
Communication und der Rest bestehen und irgendwelche einfache Steuer-
und Meßaufgaben abarbeiten. Da sehe ich zumindest die Vorteile und man
sollte sie nützen sofern man es kann:-)
Als eingefleischter Praktiker tue ich mir im Augenblick schwer mich mit
der neuen Materie vertraut zu machen. Aber vielleicht klappt es allen
anfänglichen Schwierigkeiten zum Trotz doch einmal.
Abgesehen davon hängt Vieles davon ab welche Entwicklungswerkzeuge und
uC Ressourcen vorhanden sind. Viele der neuen Tols benötigen eher
großzügige Ressourcen und sind auf kleinen uC eher mißplaziert.
Wie Arduino beweist ist der Gebrauch eines Subsets von C++ durchaus
realistisch und würde persönlich mehr Zeit und Muße dort reinstecken
wollen um zumindest auf dieser Ebene etwas kompetenter zu sein.
Die Experten auf diesen Gebiet wissen sowieso wie sie ihre
Projektprobleme lösen wollen und können und brauchen keine
Besserwisser:-)
Ok. Das wärs so ziemlich für mich was dieses Thema angeht. Ich brauche
mir nicht meine Brötchen damit zu verdienen und kann mir aussuchen was
ich noch lernen will. Vielleicht fällt doch irgendwann der Groschen. Ich
werde sicherlich verfolgen was auf diesem Gebiet noch erörtert wird.
Tut mir leid wenn ich Euch mit meinen Betrachtungen und Meinungen zu
Tode gelangweilt habe. Mir war es nur wichtig mal die andere Seite
aufzuzeigen.
Schönes Wochenende noch,
Gerhard
Ach ja ;) schrieb:> Yalu X. schrieb:>>>> Ich habe mir die Mühe gemacht, [.]einen ellenlangen Beitrag von oben>> durchzulesen ..>>>> Alle anderen dürfen ihn gerne überspringen.>> Falls es dich interessiert, ich habe bei dir nicht das Gefühl "irgendein> Geschwurbel" zu lesen im Gegensatz zu manch anderen Texten hier, die mir> reichlich wirr und ohne erkennbaren Faden erscheinen. Ich frage mich nur> gerade angesichts vieler alltäglicher Programmieraufgaben, welche> speziellen Applikationen es denn überhaupt notwendig machen den Pfad des> "normalen", intuitiven Lösungsansatzes zu verlassen, um sich einer> völlig anderen Herangehensweise bedienen zu müssen?
Weil mal das eine Paradigma Vorteile gegenüber andere in gewissen
Situationen bietet. Vor allem, was soll denn dieser "normale intuitiver
Lösungsansatz" sein? Ist das frei nach dem Moto "wer nur einen Hammer
kennt, sieht in jedem Problem nur einen Nagel"? Es gibt auch in diesem
Fall nicht diesen einen intuitiven Lösungsansatz. Jeder scheint darunter
auch etwas anderes zu verstehen, für den einen ist die
Metaprogrammierung in C++ absolut schlüssig und vorteilhaft, der andere
verabscheut gleich " aufgeblassene, bürokratische" Hochsprachen und
nimmt immer Assembler...
Oh, die Diskussion ist ja ganz woanders ...
Possetitjel schrieb:> Auch wenn das wenig bis nichts mit Wilhelm zu tun hat:>> Der Anspruch leitet sich schlicht aus der normativen Kraft> des Faktischen ab: Wenn ich die Wahl zwischen einem> unverständlichen und einem klar verständlichen Buch habe,> dann wähle ich ganz sicher nicht das unverständliche. Eins> meiner wenigen Privilegien besteht darin, mir meine Lehrer> aussuchen zu können.
Ich verstehe dieses Forum immer noch als Hilfe zur Selbsthilfe und ich
habe nicht den Anspruch hier Kapitel eines Lehrbuches abzuliefern oder
alles vorzuverdauen. Es geht mir nur um Anregungen. Wer nicht die
Vorstellungskraft hat, dahinter einen Wert zu erkennen, der ihn dazu
bringt, sich selbst(!) damit zu beschäftigen, der soll es eben sein
lassen. Wer also ein Motiv hat, kann ja fragen. Ich bin kein
Motivationstrainer sondern gehe von instrinsischer Motivation aus.
Gerade in diesem Forum!
Und alles auf einen Automaten zurückzuführen finde ich ähnlich
abenteuerlich wie das oben Yalu geschrieben hat. Ich finde die Modelle
und Werkzeuge der theoretischen Informatik sehr nützlich, vor allem,
weil man es mit Papier und Bleistift erledigen kann, allerdings kann ich
auch verstehen, dass hier ggf. das Abstraktionsvermögen anderer aufhört.
Gerhard O. schrieb:> Als eingefleischter Praktiker tue ich mir im Augenblick schwer mich mit> der neuen Materie vertraut zu machen. Aber vielleicht klappt es allen> anfänglichen Schwierigkeiten zum Trotz doch einmal.
Aus meiner Sicht sollte man sich die folgenden Fragen (ausgehend von
einer C-Welt) stellen:
* wann kann/soll der Berechnungszeitpunkt sein: Compilezeit,
Auführungszeit
* kann ich das Typsystem der Sprache modifizieren: ja/halb/nein
* wie/wann kann ich das Typsystem modifizieren: statisch im Quelltext,
durch Berechnung zur Compilzeit, zur Laufzeit
Das Typsystem ist deswegen so wichtig, weil es der Kern der
imperativ/prozeduralen Sprachen wie C oder C++ (hat noch mehr
Paradigmen) ist.
In C kann ich keine Berechnungen zur Compilezeit machen und ich kann nur
das eingebaute Typsystem verwenden. Somit ist es sehr schwer,
abstrakteren Code zu schreiben. Je komplizierter die Aufgabe, desto mehr
Abstraktion ist notwendig, um das Problem beherrschen zu können.
In C++ kann man:
* Berechnungen zur Compilezeit durchführen: der Compiler "interpretiert"
den Code im Moment des Compilierens
* das Typsystem modifizieren, etwa einen Datentyp erfinden, der beim
inkrementieren bei bspw. 10 saturiert oder zirkulär die Werte 0...9
annimmt. Oder einen Datentyp String, der von der C-orientieren
Sichtweise einzelner Zeichen abstrahiert, die es erlaubt, Strings zu
addieren/konkatenieren (+) oder lexikografisch zu vergleichen (<).
* die Modifikation des Typsystems kann im Quelltext statisch stattfinden
(Klassen erstellen) oder zur Compilezeit "berechnet" werden. Wenn es
bspw. bekannt ist, dass ein Array maximal 100 Elemente enthält, reicht
als DT für den Index ein uint8_t aus, es muss kein size_t sein. Das kann
der Compiler zur Compilezeit selbst ermitteln.
Dies sind ein paar Dinge, die das Abstraktionsniveau erhöhen und damit
Fehler vermeiden helfen, z.B. unerwünschter Wrap-around bei zu kleinen
Ganzzahltypen, und die erstmal mit OOP in engeren Sinne, also
Laufzeitpolymorphie (Liskov) gar nichts zu tun haben.
> Ok. Das wärs so ziemlich für mich was dieses Thema angeht.
Vielleicht sind die o.g. Dinge eine kleine Motivation, etwas tiefer
einzusteigen.
Wilhelm M. schrieb:> Vielleicht sind die o.g. Dinge eine kleine Motivation, etwas tiefer> einzusteigen
Wilhelm,
Ist es schon und bedanke mich auch für Deine Hinweise.
Aber der Appettit kommt mit dem Essen und es ist notwendig eine
Entwicklungsumgebung zu installieren die das auch kann. Ich kann nur
lernen wenn ich mich damit praktisch befassen kann. Nur darüber zu lesen
ist zwecklos für mich.
Ich hatte vergessen zu fragen ob es Sinn hätte am PC mit Visual Studio
zuarbeiten. Das dürfte so ziemlich uptodate sein. Zum Lernen wäre das
ideal weil es in Windows lauffähig sein müßte.
Den CYgwin GCC compiler wollte ich installieren, hatte aber Internet
Verbindungsprobleme und das Installierprogramm gab auf. Da müßte ich mal
rausfinden warum das nicht geht.
Also halte mir den Daumen,
Gerhard
Gerhard O. schrieb:> Ich hatte vergessen zu fragen ob es Sinn hätte am PC mit Visual Studio> zuarbeiten. Das dürfte so ziemlich uptodate sein. Zum Lernen wäre das> ideal weil es in Windows lauffähig sein müßte.
Natürlich, man lernt auf dem PC, und MSVS ist ok, wenn es recht aktuell
ist.
> Also halte mir den Daumen,> Gerhard
Klaro - und bei Fragen ... fragen
Wilhelm M. schrieb:> Gerhard O. schrieb:>>> Ich hatte vergessen zu fragen ob es Sinn hätte am PC mit Visual Studio>> zuarbeiten. Das dürfte so ziemlich uptodate sein. Zum Lernen wäre das>> ideal weil es in Windows lauffähig sein müßte.>> Natürlich, man lernt auf dem PC, und MSVS ist ok, wenn es recht aktuell> ist.>>> Also halte mir den Daumen,>> Gerhard>> Klaro - und bei Fragen ... fragen
Ok. Danke. Werde Dich beim Wort nehmen:-)
Im vorherigen Beitrag beschriebst Du die Compile Möglichkeiten. Das hört
sich toll an obwohl ich mir im Augenblick noch wenig darunter vorstellen
kann wie das im Einzeln vor sich geht. Deshalb wäre Experimentation
wahrscheinlich der beste Weg um dafür ein praktisches Gefühl dafür zu
bekommen.
Soweit es uC angeht wäre wahrscheinlich Atollic die einzige Umgebung wo
das vielleicht auch mit uC wie STM32 Typen funktioniert. Da müßte man
mal recherchieren inwieweit deren GCC Compiler uptodate ist.
PC Apps programmieren tue ich eigentlich sonst nicht.
Gerhard O. schrieb:> Soweit es uC angeht wäre wahrscheinlich Atollic die einzige Umgebung wo> das vielleicht auch mit uC wie STM32 Typen funktioniert. Da müßte man> mal recherchieren inwieweit deren GCC Compiler uptodate ist.
GCC für ARM hat auch ein libstdc++.
Aber das Testen Deiner Programme ist doch auf dem PC in einer IDE viel
einfacher. Später machst Du den Übergang zu µC.
TriHexagon schrieb:> was soll denn dieser "normale intuitiver> Lösungsansatz" sein?
Wie ja jeder weiß, entsteht Software stets ingenieursmäßig durch
ausgefuchstes, intensives Modellieren streng nach Entwicklungsplan, wie
aus dem Lehrbuch und jeder der auch nur eine Zeile Code schreibt, bevor
nicht auch der letzte Detailentwurf ausgearbeitet und auf Folie
präsentiert ist, der ist ein ganz, ganz schlimmer Mensch. :)
Oder vielleicht eher doch nicht?
Das wäre dann der erwähnte eher intuitive Lösungsansatz. Soll heißen,
natürlich schon ein paar Gedanken machen wo es hingehen soll, aber dann
auch zügig anfangen zu Programmieren, um schnell erste Ergebnisse zu
haben.
Wie jeder persönlich da vorgeht (oder vorgehen muss, weil's der
Arbeitgeber bestimmt) und welcher Mittel er sich dabei bedient muss
natürlich jeder für sich selber entscheiden. Yalu beispielsweise baut
sich gedanklich seine kleinen Maschinchen, die er anschließend mit Daten
füttert, in der Hoffnung, dass hinterher auch das "richtige" bei
rauskommt. Inzwischen hat er diesen Ansatz aber wohl hinter sich
gelassen.
Gerhard greift auf den Fundus seiner wiederverwendbaren und
verlässlichen Codebasis zurück. Dr. Sommer wird seinen C++ -Kasten in
Schwung bringen. Von einem hier in Forum las ich mal Nim hätte es ihm
angetan. Der Admin (Schwarz) schwört wohl auf Python und Ruby (las ich
mal). Es soll auch manche hier geben, die ihr Glück in einem
Bezahl-BASIC gefunden haben. Mein Eindruck ist jeder ist da seinen
Gewohnheiten irgendwie erlegen und nimmt halt das was er beherrscht. Was
natürlich niemandem daran hindert auch neue Pfade auszuprobieren.
Was den Hammer betrifft, eine Software ist nicht ein simples
Metall-Hau-Werkzeug, dass jeder in schneller Anlernmanier mal eben
austauschen kann. Eine lieb gewonnene Radfahr-Gewohnheit auf dem eigenen
Rennrad lässt sich auch nicht so einfach gegen die auf einem (fremden)
Tandem eintauschen. Das ist nun mal nicht das gleiche bzw. fühlt sich
völlig anders an. Genau so sieht es auch mit einer langjährig eingeübten
Programmiersprache oder einem Programmier-Paradigma wie OOP vs.
Prozedurales Programmieren aus. So ein Wechsel ist nicht mal eben auf
die Schnelle gemacht. Nicht wenige scheitern ja schon am Eingewöhnen an
FreeCAD oder an den MS Office Ribbons ;-) oder wie ich letztens las
proggen lieber auf der Linux Kommandozeile in C, weil's so schön einfach
geht anstatt sich mit der aufgeblasenen MS Visual C++ IDE
herumzuschlagen. :)
Es kommt hinzu, mit zunehmendem Alter nimmt die einstige studentische
Ausprobier-Euphorie auch eher steil ab. Da ist der Alltag einfach anders
(straffer) strukturiert und die Zeit für viel Experimentierfreude nicht
mehr so vorhanden. Also nimmt man was man kennt und gut ist.
:)
Wilhelm M. schrieb:> Gerhard O. schrieb:>>> Soweit es uC angeht wäre wahrscheinlich Atollic die einzige Umgebung wo>> das vielleicht auch mit uC wie STM32 Typen funktioniert. Da müßte man>> mal recherchieren inwieweit deren GCC Compiler uptodate ist.>> GCC für ARM hat auch ein libstdc++.> Aber das Testen Deiner Programme ist doch auf dem PC in einer IDE viel> einfacher. Später machst Du den Übergang zu µC.
Das stimmt und hatte ich sowieso vor. Bevor ich nicht ein gewisses Maß
Selbstvertrauen diesbezüglich erworben habe, hätte es wenig Sinn auf dem
uC zu experimentieren.
Naja. Vielleicht wird es besser gehen wie ich mir es ausmale. Allerdings
wird ein Teil der Bemühungen Eine Dokubasis zum Nachschlagen aufzubauen
da ich zur Zeit noch nichts habe.
Wie ist eigentlich z.B mit der Stringdoku?
Wenn ich jetzt eine String search machen wollte, geht das mit
trickreicher Operator Magie oder Funktionsaufruf alleine? Das sind so
die Fragen die ich mir beantworten muß. Auch wie ein Minimal Program
aufgebaut sein müßte und die notwendigen Header Files. Da habe ich noch
einiges vor mir. Naja, Dein Beispielprogram vorher, gibt mir da schon
einen Start.
Laßt Euch von mir überraschen...
Ach ja ;) schrieb:> Oder vielleicht eher doch nicht?
Ich bin ein ganz schlimmer Mensch:-)
Da ich meist meine eigene HW entwickle denke ich auch schon parallel mit
wie die HW Gestaltung Aspekte die zukünftige SW beeinflussen würde um
unnötige SW Klimmzüge zu vermeiden. Dann, wenn die HW existiert teste
ich alles durch und schreibe und teste mal zuerst die Treiber oder
verwende schon vorhandene Treiber von vorherigen Projekten, so daß man
die Peripherie ansprechen kann. Dafür habe ich mir ein Standard Test
Program geschneidert mit dem ich meine HW dann virtualisieren kann und
testen. Da habe ich dann sofort Zugang auf die meisten Peripherien des
uC, extern oder intern.
Die eigentliche SW wird erst dann wirklich geplant und detailliert. Da
man zu diesem Zeitpunkt weiß was HW mäßig funktioniert oder nicht, macht
dann die spätere Arbeit viel weniger nervig.
Carl D. schrieb:>> Es interessiert mich keinen Deut, wenn der Autor des>> ersten ein verkanntes Genie, der Autor des zweiten>> Buches aber nur gutes Mittelmaß ist.>> Warum liest und kommentierst du dann das erste Buch?
Das tue ich nicht.
Ich habe DIR geantwortet, nicht Wilhelm oder sonstwem.
Es war DEINE elitäre Behauptung, die "Pioniere" könnten
nicht auf jeden Nachzügler warten.
Meine Antwort DARAUF ist: Wenn sich die "Pioniere" zu
fein sind, sich allgemeinverständlich auszudrücken,
sollen sie nicht rumheulen, dass man sie nicht versteht.
Ursache -- Wirkung. Kausalität.
Mit Wilhelm hat das nix zu tun. Mich nerven Deine elitären
Unterstellungen.
Wilhelm M. schrieb:> Possetitjel schrieb:>> Auch wenn das wenig bis nichts mit Wilhelm zu tun hat:>>>> Der Anspruch leitet sich schlicht aus der normativen Kraft>> des Faktischen ab: Wenn ich die Wahl zwischen einem>> unverständlichen und einem klar verständlichen Buch habe,>> dann wähle ich ganz sicher nicht das unverständliche. Eins>> meiner wenigen Privilegien besteht darin, mir meine Lehrer>> aussuchen zu können.>> Ich verstehe dieses Forum immer noch als Hilfe zur Selbsthilfe
Du hast aber schon gelesen, dass ich den Abschnitt überschrieben
habe mit "Auch wenn das wenig bis nichts mit Wilhelm zu tun hat"?
> und ich habe nicht den Anspruch hier Kapitel eines Lehrbuches> abzuliefern oder alles vorzuverdauen. Es geht mir nur um> Anregungen.
Das verstehe ich.
Eine Anregung hat ja aber den Sinn, Lust auf mehr zu machen.
Das erreichen Deine Anregungen aber bei mir nicht, sie
schrecken mich eher ab.
Der Grund dafür liegt darin, dass Deine Anregungen zu wenig
an das anknüpfen, was ich kenne.
Das kannst Du natürlich als Unverschämtheit und als Anspruchs-
haltung interpretieren -- aber es ist erstmal nur eine sachliche
Aussage. Was Du damit anfängst, ist Deine Sache.
> Und alles auf einen Automaten zurückzuführen finde ich> ähnlich abenteuerlich wie das oben Yalu geschrieben hat.
Steht Dir völlig frei.
Im Gegensatz zu Dir formuliert Yalu seine Zweifel und Fragen
an mich ausführlich und gibt mir die Chance, mich zu erklären.
> Ich finde die Modelle und Werkzeuge der theoretischen> Informatik sehr nützlich,
Ich auch.
Zu den Modellen und Werkzeugen der theoretischen Informatik
gehören allerdings auch die Automaten. Insofern verstehe ich
Deine Bemerkung von oben nicht. Immerhin ist die Turing-Maschine
auch ein Automat.
Ich habe auch nirgendwo gegen die theoretische Informatik
polemisiert. Meine Aussage war nur, dass die Bücher über
PROGRAMMIERSPRACHEN, die ich kenne, Scheisse sind, weil sie
sich in Details verlieren, die die Konzepte eher verdecken
als erklären. Das hat wenig bis nichts mit theoretischer
Informatik zu tun.
> vor allem, weil man es mit Papier und Bleistift erledigen> kann, allerdings kann ich auch verstehen, dass hier ggf.> das Abstraktionsvermögen anderer aufhört.
???
Ich pflege die Automatentheorie, die ich brauche, fast immer
mit Papier und Bleistift zu erledigen.
Und woher weisst Du, wo mein Abstraktionsvermögen endet?
Possetitjel schrieb:> Carl D. schrieb:>>>> Es interessiert mich keinen Deut, wenn der Autor des>>> ersten ein verkanntes Genie, der Autor des zweiten>>> Buches aber nur gutes Mittelmaß ist.>>>> Warum liest und kommentierst du dann das erste Buch?>> Das tue ich nicht.>> Ich habe DIR geantwortet, nicht Wilhelm oder sonstwem.> Es war DEINE elitäre Behauptung, die "Pioniere" könnten> nicht auf jeden Nachzügler warten.
Den Begriff "Pionier" haben ich als leicht überzeichneten Gegensatz zu
den "was wir immer gemacht haben, hat uns immer gereicht"-Schreibern
gewählt. Ich hab nichts gegen diese, möchte mich im Gegenzug von ihnen
aber auch nicht bremsen lassen.
> Meine Antwort DARAUF ist: Wenn sich die "Pioniere" zu> fein sind, sich allgemeinverständlich auszudrücken,> sollen sie nicht rumheulen, dass man sie nicht versteht.> Ursache -- Wirkung. Kausalität.
Sie sind "sich zu fein" auch denen, denen die Happen warum auch immer zu
groß sind, diese vorzukauen.
> Mit Wilhelm hat das nix zu tun. Mich nerven Deine elitären> Unterstellungen.
Wenn es elitär sein sollte, sein Hirn für mehr zu benutzen als die
Ausrede "ich kann's nicht probieren, weil meine 9 Kollegen das nie
verstehen", dann muß ich mich damit abfinden.
Aber was soll's, ich hatte eigentlich den Plan, mal ein Beispiel zu
bauen, das komplex genug ist, um die Vorteile erkennbar zu machen und
einfach genug, daß es auch mit leichter mental-Gastritis verdaubar ist.
Offenbar kann ich mir die Zeit sparen.
Gerhard O. schrieb:> Naja. Vielleicht wird es besser gehen wie ich mir es ausmale. Allerdings> wird ein Teil der Bemühungen Eine Dokubasis zum Nachschlagen aufzubauen> da ich zur Zeit noch nichts habe.>> Wie ist eigentlich z.B mit der Stringdoku?
Die offizielle Doku zur Sprache und zur libstdc++ findest Du hier:
http://en.cppreference.com/w/> Wenn ich jetzt eine String search machen wollte, geht das mit> trickreicher Operator Magie oder Funktionsaufruf alleine?
Mmh, jetzt bin ich etwas verwirrt: ich war davon ausgegangen, dass Du
ein Grundverständnis von C++ hast?
Der Typ std::string ist kein primitiver DT in C++, sondern in der
libstdc++ definiert (eigentlich als template-Spezialisierung).
Grundsätzlich gilt in der libstdc++ eine Zweiteilung in (generische)
Algorithmen und Datentypen. Das Bindeglied zwischen beidem sind
Iteratoren. Iteratoren kann man im ersten Ansatz als verallgemeinerte
Zeiger ansehen (DT mit den Op * ,-> ,++, !=).
Eine Substring-Suche findest Du als Elementfunktion des DT std::string.
Andere Algorithmen auf den Containern in der Algorithmus-Teilbibliothek.
Ist das jetzt alles neu für Dich?
Würde auch vorschlagen, das Du andere Threads eröffnest, um Deine Fragen
zu stellen.
Wilhelm,
Um diese Zeit hätte ich jetzt keine Antwort mehr erwartet:-) bei mir ist
es fast 23:00 Uhr.
Wilhelm M. schrieb:> Gerhard O. schrieb:>>> Naja. Vielleicht wird es besser gehen wie ich mir es ausmale. Allerdings>> wird ein Teil der Bemühungen Eine Dokubasis zum Nachschlagen aufzubauen>> da ich zur Zeit noch nichts habe.>>>> Wie ist eigentlich z.B mit der Stringdoku?>> Die offizielle Doku zur Sprache und zur libstdc++ findest Du hier:>> http://en.cppreference.com/w/
Danke.
>>> Wenn ich jetzt eine String search machen wollte, geht das mit>> trickreicher Operator Magie oder Funktionsaufruf alleine?>> Mmh, jetzt bin ich etwas verwirrt: ich war davon ausgegangen, dass Du> ein Grundverständnis von C++ hast?
Noch nicht viel weil ich bis jetzt uC nur in C gequält habe. Ich
modifizerte allerdings die Core Serial vom Arduino um RS485 native zu
unterstützen. Das ist auch alles und kam auch ganz gut zurecht damit
weil da ja schon ein funktionierendes Beispiel vorhanden war das ich nur
erweitern mußte.
>> Der Typ std::string ist kein primitiver DT in C++, sondern in der> libstdc++ definiert (eigentlich als template-Spezialisierung).>> Grundsätzlich gilt in der libstdc++ eine Zweiteilung in (generische)> Algorithmen und Datentypen. Das Bindeglied zwischen beidem sind> Iteratoren. Iteratoren kann man im ersten Ansatz als verallgemeinerte> Zeiger ansehen (DT mit den Op * ,-> ,++, !=).>> Eine Substring-Suche findest Du als Elementfunktion des DT std::string.
Ok. Werde ich nachschauen. Ich beginne zu verstehen. Das ist definitiv
sehr "powerful".
> Andere Algorithmen auf den Containern in der Algorithmus-Teilbibliothek.
Vielen Dank. Das werde ich mir gleich vorknöpfen weil es für mich
praktisch wichtig ist.
>> Ist das jetzt alles neu für Dich?
Absolut. Bis jetzt kam ich ja mit C immer zurecht. Will aber meinen
Horizont doch erweitern weil mir einige C++ Sachen beim Arduino als sehr
nützlich vorkamen.
>> Würde auch vorschlagen, das Du andere Threads eröffnest, um Deine Fragen> zu stellen.
Da hast Du recht. Werde ich machen.
Beitrag "Praktische C++ Anwendungsfragen"
Jedenfalls bin ich Dir für alle Deine Ratschläge und Informationen
dankbar.
Gruß,
Gerhard
Roland F. schrieb:> Was meinst du mit "Details"?
u.a.:
- "using namespace std;" in C++
- "int" für Array-Indices
- Makros für alles und jedes statt inline-Funktionen und Konstanten
- Nutzung von "int" statt "int32_t" o.ä.
- *NULL
- char x [7]; x [3] = NULL;
- int x = ... ; char lowerByte = ((char*) &x) [0];
- printf ("%d\n", irgendEinPointer);
... sieht man sehr häufig. Das könnte man gerne besser lehren...
Wegen C++: Das lernt man am Besten mit einem guten Buch. Viele Bücher
sind schlecht. Hier ist eine Liste guter Bücher:
https://stackoverflow.com/a/388282
Dr. Sommer schrieb:> Nutzung von "int" statt "int32_t"
Kann aber gut und gern sinnvoll sein. int32_t schreibt halt zwingend
vor, dass es genau 32 Bits sein müssen – auch dann, wenn das für
irgendeine Architektur vielleicht gerade nicht optimal ist.
int_fast32_t würde sagen: „nimm mindestens 32 Bits, aber es soll schnell
sein“. Das ist das, was man meistens brauchen würde an dieser Stelle.
"int" allein hat aber eine hinreichend garantierte Minimalgröße, dass
es für viele Fälle genügt, und die Annahme ist, dass es für eine
bestimmte Architektur die Größe ist, die auf dieser Maschine am
besten verarbeitbar ist (auf einem AVR sind es daher 16 Bits, auf
einem ARM 32, auf anderen können es auch 64 sein).
Aber ich gebe dir Recht: genau solche Abwägungen müsste man natürlich
besser unter die Leute bringen.
Jörg W. schrieb:> Kann aber gut und gern sinnvoll sein
Klar. Aber die meisten nutzen, wie in Java, für alles int. Man sollte
wissen wann es sinnvoll ist und wann nicht ist. Statt int würde ich aber
auch lieber int_least16_t schreiben, hat die gleiche Bedeutung aber es
zeigt klarer was man haben will.
Possetitjel schrieb:>> Für andere aber nicht. Ich merke deutlich die Unterschiede>> im Denken bei der Zusammenarbeit mit Ingenieuren.>> Nur interessehalber: Welche sind das? Bzw. wie zeigen sie> sich?
Schwierig in Worte zu fassen. Ein Versuch:
- Ingenieure denken in Bauplänen und Komponenten. Alles was nicht als
Blockdiagramm darstellbar ist ist für den Ing kaum fassbar. Software
lässt sich aber nur sehr begrenzt so darstellen, oder immer nur eine
Sichtweise davon...
- Wenn für den Ing zwei Komponenten irgendwie zusammenpassen, ist alles
ok. Aus Software-Sicht ist die Kombination beliebiger Teile oft nicht
sinnvoll, was nicht so leicht vermittelbar ist. Bspw. einen ESP32 an
einem R-PI mit Linux anzuschließen ist nur auf den 3. Blick "irgendwie
komisch".
- Hardware lässt sich gut wasserfall-artig entwickeln, von Anforderungen
bis Tests. Ist bei Software oft weniger angemessen, und agile Prozesse
passen ggf. nicht gut in ein Ingenieurs-Unternehmen. Software ist auch
nie wirklich fertig.
- Für Ing.-Arbeiten lassen sich wunderbar ToDo-Listen und
Arbeitsvorgänge planen - à la der Abteilungsleiter plant wer was wann
macht - das ist bei Software und den komplexen Abhängigkeiten schwierig.
- Ing.-Arbeit ist oft "richtige Arbeit", die man Schritt für Schritt
abarbeiten kann. SW-Entwicklung ist oft ein kreativer Prozess mit
ungewissem Weg, Dauer und Ende.
- Ings haben oft kaum das Deployment/Inbetriebnahme im Blick. Als
Embedded-Entwickler darf man sich dann mit Platinen befassen, die keine
Test-LED's/Taster, Testpunkte, komische JTAG-Stecker, allgemein winzige
unpraktische Stecker haben. Der klitzekleine "SW-Entwicklung"-Schritt
zwischen Löten und Einbauen wird da gern übersehen.
- Ings haben nicht so das Gefühl für Fehlersuche. Wenn da was nicht
klappt stehen die oft ratlos da. Als Informatiker hat man mehr so das
Verlangen möglichst viele Informationen zu sammeln um das Problem
einzugrenzen, so klärt sich schon vieles.
Das soll alles keine Beleidigung sein, sind nur ein paar Erfahrungen.
Ings können haben bestimmt auch genug Probleme mit Informatikern.
Natürlich hängt das alles stark vom Einzelfall ab, und die Probleme
lassen sich mit Kommunikation und Organisation angehen. Aber dran denken
muss man...
Dr. Sommer schrieb:> Funktioniert nicht mit Strings die 0-Bytes enthaltenMarkus F. schrieb:>> ... Strings die 0-Bytes enthalten...>> das ist für C-Programmierer ein Oxymoron.
Ist es nicht. Jeder C-String enthält ein 0-Byte, selbst ein leerer
String.
Aber eben nur eins.
Ein Byte-Array, das mehrere 0-Bytes oder auch keins enthalten kann, ist
eben kein String, sondern ein Mem-Block. Dazu gibt es eigene Funktionen.
Die haben aber den Nachteil, dass sie zwingend als zweiten Parameter
eine Länge brauchen, während zum Lesen eines Strings ein Pointer genügt.
Zum Schreiben von Strings ist ein zweiter Pointer als Begrenzung oder
die Restlänge des Puffers sinnvoll.
Da Strings die Aufgabe haben, sowohl von Menschen als auch von Maschinen
lesbar und schreibbar zu sein, ist die Sonderfunktion des 0-Bytes keine
Beeinträchtigung.
Yalu X. schrieb:> Ich habe mir die Mühe gemacht, deinen ellenlangen Beitrag> von oben durchzulesen,
Ohh. Vielen Dank.
> jetzt musst du dasselbe auch mit meinem tun ;-)
Sehr gern.
> Wenn ich dich richtig verstehe, versucht du, sämtliche> Eigenschaften von Programmiersprachen auf Automaten> abzubilden, um sie dadurch besser zu verstehen.
Ähh... Nein.
Ich habe die Beobachtung gemacht, dass BESTIMMTE Eigen-
schaften von Programmiersprachen für mich sehr viel
leichter verständlich werden, wenn ich sie auf (endliche)
Automaten abbilde.
Das Verständnis fällt mir SO viel leichter, dass ich
mich ernsthaft frage, warum die übliche Darstellung
auf eine so hirnrissig komplizierte Weise erfolgt.
> Kann es sein, dass du dich damit selber blockierst und> so somit genau das Gegenteil von dem erreichst, was du> eigentlich anstrebst?
Sicher kann das sein -- aber erlaube die Gegenfrage:
Was bringt Dich auf den Verdacht, es sei so?
> Was du in deinen Beispielen mittels Automaten beschreibst,> sind im Wesentlichen Ablaufstrukturen (Sprünge, Unter-> programmaufrufe, Objekte mit Memberfunktionen, Parallelität> usw.).
Hmm, ja.
> Im Gegensatz zu Assembler und Ur-Fortran zeichnen sich> moderne Sprachen aber durch weit mehr als nur die von> ihnen unterstützten Ablaufstrukturen aus, als da wären:>> - Datentypen (numerisch, textuell, primitiv, zusammengesetzt,> ...)>> - Typsysteme (stark, schwach, statisch, dynamisch, flach,> hierarchisch, ...)>> - Möglichkeiten der Metaprogrammierung (Lisp-Makros,> C++-Templates, ...)>> - u.v.m.
"If it's not broken, don't fix it."
Warum sollte ich Dinge umdeuten, mit denen ich in der
traditionellen Formulierung keine Verständnisprobleme
habe?
Nehmen wir die Datentypen: Ich habe da nie tiefer drüber
nachgedacht, aber man kennt es ja aus der Physik, dass eine
physikalische Größe aus Zahlenwert und Einheit besteht, und
dass man als Folge dessen nur Größen rechnerisch verknüpfen
darf, deren Einheiten kompatibel sind. (Dafür gibt es sogar
eine m.o.w. algebraische Begründung.)
Das ist ja letztlich genau das, was auch Datentypen im
Computer bewirken; das ist eine vertraute Geschichte.
Warum sollte ich das auf Krampf umdeuten wollen?
[...]
> Ich habe deswegen lange nach einem besseren Ersatz für> diese Maschinchen gesucht und schließlich auch gefunden:>> Mathematische Modelle
Ich verstehe die Worte, nicht aber ihren Sinn: Ein Automat
IST doch (auch bzw. primär) ein mathematisches Modell --
nämlich ein Quintupel (X, Y, Z, f, g) mit bestimmten Eigen-
schaften.
Nur hat dieses mathematische Modell den großen Vorzug, dass
ich sehr einfache elektronische Realisierungen für wenige
Cent bei der eingetragenen Kauffrau in Sande kaufen kann.
Wann hat man dieses Privileg schon mal: Anschauungsmodelle
für mathematische Konzepte, die man im Bastlerladen kaufen
kann?
Und ein weiterer Vorzug: Mir als E-Techniker ist das Modell
des endlichen Automaten vertraut -- also warum sollte ich
dieses Wissen nicht in Anschlag bringen, wenn es möglich
ist?
> Endgültig die Augen aufgegangen sind mir, als ich begann,> mich mit funktionaler Programmierung zu beschäftigen. In> der reinen FP gibt es weder Abläufe noch Zustände, weswegen> die Vorstellung von Maschinchen schon per se zu nichts> führen kann.
Ich bin... verwirrt.
> Mit mathematische Modellen hingegen kann man einige Dinge> tun, die mit den Maschinchen in meinem Kopf kaum möglich> sind:
Wahrscheinlich missverstehe ich Deine Intention gründlich,
aber was ist Automatentheorie für Dich? Sowas wie die
Backförmchen für die Kindergartenkinder? Cargo-Mathematik
(--> Cargo-Kult) für Debile (=Elektrotechniker)?
[...]
> Immer wieder fallen mir bei schwierigen Problemen weitere> Wege ein, die zwar abstrakt anmuten, aber letztendlich> dazu geeignet sind, hinderliche Knoten in Gehirnwindungen> zu lösen und damit die Problemstellung zu vereinfachen.
Naja... ist das nicht die Stärke jeder guten, verständigen
Abstraktion?
"Es gibt nichts praktischeres als eine gute Theorie."
> Und das Beste dabei: Die Erkenntnisse, die man dabei gewinnt,> lassen sich nicht nur auf die FP, sondern mit leichten> Einschränkungen auch auf die klassische Programmierung in> C oder C++ anwenden.
Ich weiss immer noch nicht, worauf Du mit der funktionalen
Programmierung hinauswillst.
Die Sache ist faszinierend, ja -- unter anderem deshalb,
weil sie (genau wie die Deutung durch endliche Automaten)
ohne "Algorithmen" und die dadurch entstehenden "parasitären"
Zustände auskommt.
Vielleicht mache ich einen Fehler, aber ich sehe noch nicht,
wie mir die FP z.B. im Kontext der OOP helfen sollte.
> Was ich damit ausdrücken möchte: Die Informatiker, deren> Geschwurbel du nicht verstehst, sind entweder tatsächlich> Dummschwätzer oder Angeber, oder aber sie denken in Modellen,> die sie persönlich zwar befähigen, selbst schwierigste> Probleme zu lösen, die sich aber leider nicht in deine Welt> der Automaten übersetzen lassen.
Nein, weder -- noch. Völlig anders.
Ich habe kein grundsätzliches Problem mit der theoretischen
Informatik. Das ist halt mathematischer Stoff genau wie
Feldtheorie, Numerik oder Algebra. Es ist hart, sich den
Stoff zu erarbeiten, aber es lohnt sich in der Regel, weil
man sich dauerhaftes Hintergrundwissen aufbaut. Das Hinter-
grundwissen ist zwar interessant, aber kurzfristig nicht
unmittelbar praktisch anwendbar.
Unmittelbar praktisch anwendbar wäre die zuverlässige
Beherrschung einer Programmiersprache. Leider habe ich ein
MASSIVES Problem mit den meisten Büchern, die mir eine
Programmiersprache beibringen wollen. Die Darstellungen
kleben dermaßen schrecklich an syntaktischen Details und
geben so wenig Einblick in die hinterliegenden Konzepte,
dass ich i.d.R. nach wenigen Seiten einen Wutanfall
bekomme.
Wenn ich von Digitaltechnik keine Ahnung hätte, würde ich
mich schätzungsweise deprimiert und demütig in die Ecke
setzen und mich schämen, weil ich so dumm bin.
Sehr zum Nachteil meiner Mitmenschen HABE ich aber gewisse
Grundkenntnisse in Automatentheorie. Gestützt auf diese
Kenntnisse fährt mir ein ums andere Mal in die Nase, dass
die angewandten Informatiker, die die Bücher verfasst
haben, KONSEQUENT alle die schönen, einfachen, klaren
theoretischen Modelle ignorieren, die ihre Fachkollegen
aus der theoretischen Informatik und der Digitaltechnik
bereitgestellt haben.
Man kann (nicht alle, aber) viele Sachverhalte, mit denen
übliche Programmiersprachen hantieren, klar und verständlich
in den Begriffen der Automatentheorie darstellen -- ABER
DAS WIRD NICHT GEMACHT!
Wozu wurden die Begriffe der Automatentheorie entwickelt,
wenn sie dann nicht bei einer der häufigsten Tätigkeiten
in der Informatikausbildung -- nämlich dem Lehren von
Programmiersprachen -- verwendet werden?
Hallo,
Dr. Sommer schrieb:> Wegen C++: Das lernt man am Besten mit einem guten Buch. Viele Bücher> sind schlecht. Hier ist eine Liste guter Bücher:> https://stackoverflow.com/a/388282
Das Problem C++ (oder auch andere Programmiersprachen) zu lernen ist
nicht ein gutes Buch über C++ durch zuarbeiten, sondern die hinter den
neueren Versionen von C++ stehenden Programmierparadigmen zu verstehen.
Jedes mal wenn ich versuche diese Konzepte zu begreifen, muss ich
feststellen, das sich die entsprechende Literatur in syntaktischen
Einzelheiten der Programmiersprache verliert, anstatt erst mal
grundsätzlich zu erklären welche eigentliche Idee hinter bestimmten
Sprachkonstrukten (und den damit verbundenen Datentypen) steht. Mir geht
es da genau wie Possetitjel,
Zitat:
> Leider habe ich einMASSIVES Problem mit den meisten Büchern, die mir> eine Programmiersprache beibringen wollen. Die Darstellungen kleben> dermaßen schrecklich an syntaktischen Details und geben so wenig> Einblick in die hinterliegenden Konzepte, dass ich i.d.R. nach wenigen> Seiten einen Wutanfall bekomme.
rhf
Roland F. schrieb:> Das Problem C++ (oder auch andere Programmiersprachen) zu lernen ist> nicht ein gutes Buch über C++ durch zuarbeiten, sondern die hinter den> neueren Versionen von C++ stehenden Programmierparadigmen zu verstehen.> Jedes mal wenn ich versuche diese Konzepte zu begreifen, muss ich> feststellen, das sich die entsprechende Literatur in syntaktischen> Einzelheiten der Programmiersprache verliert, anstatt erst mal> grundsätzlich zu erklären welche eigentliche Idee hinter bestimmten> Sprachkonstrukten (und den damit verbundenen Datentypen) steht. Mir geht> es da genau wie Possetitjel,
Die Menge der primitiven DT ist ja doch sehr einfach und gering, dann
gibt es noch die abgeleiteten Typen und die modifier
const/volatile/mutable, s.a.:
http://en.cppreference.com/w/cpp/language/type
Nur diese Typen haben einen direkten Bezug zu Sprachkonstrukten.
Oder meinst Du die Templates der libstdc++?
Roland F. schrieb:> Das Problem C++ (oder auch andere Programmiersprachen) zu lernen ist> nicht ein gutes Buch über C++ durch zuarbeiten, sondern die hinter den> neueren Versionen von C++ stehenden Programmierparadigmen zu verstehen.> Jedes mal wenn ich versuche diese Konzepte zu begreifen, muss ich> feststellen, das sich die entsprechende Literatur in syntaktischen> Einzelheiten der Programmiersprache verliert, anstatt erst mal> grundsätzlich zu erklären welche eigentliche Idee hinter bestimmten> Sprachkonstrukten (und den damit verbundenen Datentypen) steht. Mir geht> es da genau wie Possetitjel,
Das kann man meistens nicht den Büchern/Autoren anlasten. Es ist z.B.
schwer die objektorientierten Features von C++ zu verstehen, ohne
grundlegendes OOP Kenntnisse. Es ist allerdings nicht sinnvoll den
kompletten Inhalt eines C++ und eines OOP Lehrbuch in ein einzelnes Buch
zu packen, denn niemand möchte für Grundlangen ein 3000 Seiten 200€ Buch
haben. Und was würde man dann mit den ganzen anderen Themen wie
prozeduale, funktionale und generische Programmierung machen? Alles in
ein Buch packen? Es müssen also immer mehrere Bücher benutzt werden.
mh schrieb:> Roland F. schrieb:>> Das Problem C++ (oder auch andere Programmiersprachen) zu lernen ist>> nicht ein gutes Buch über C++ durch zuarbeiten, sondern die hinter den>> neueren Versionen von C++ stehenden Programmierparadigmen zu verstehen.> Das kann man meistens nicht den Büchern/Autoren anlasten. Es ist z.B.> schwer die objektorientierten Features von C++ zu verstehen, ohne> grundlegendes OOP Kenntnisse.
Das hat sich C++ nun mal leider selber zu eigen gemacht. C#
beispielsweise hat den Vererbungsrattenschwanz auf ein notwendiges Maß
eingeschränkt und es scheint auch zu gehen. Wenn C# kritisiert wird,
dann stets z.B. weil man der automatisierten, hausinternen
Daten-Müllabfuhr genannt GC misstraut bzw. sie für wenig performant
hält, aber nicht, weil man wie bei C++ rückwirkend bis zu August dem
Starken noch Erbansprüche seiner Klasse beifügen kann.
C++ ist für viele anscheinend nur dann erträglich und alltagstauglich,
indem sie es als besseres C verwenden. Das wird auch immer wieder
zugegeben und ist ja auch nicht verwerflich, wirft aber halt Fragen auf
bezüglich des Konzepts und der daraus abgeleiteten Lerntauglichkeit
dieser Sprache. Und die vielen recht oberflächlichen C++ Bücher
untermauern letztlich doch diesen Eindruck. Auch den Autoren dieser
Bücher scheint es offensichtlich große Mühe zu bereiten, die wahren
Vorteile von C++ dem geneigten Leser verständlich zu vermitteln.
Korrektur, muss heißen
" ... aber nicht, weil man NICHT wie bei C++ rückwirkend bis zu August
dem
Starken noch Erbansprüche seiner Klasse beifügen kann."
Possetitjel schrieb:>> Wenn ich dich richtig verstehe, versucht du, sämtliche>> Eigenschaften von Programmiersprachen auf Automaten>> abzubilden, um sie dadurch besser zu verstehen.>> Ähh... Nein.
Ok, dann habe ich dich wahrscheinlich komplett missverstanden.
> Ich habe die Beobachtung gemacht, dass BESTIMMTE Eigen-> schaften von Programmiersprachen für mich sehr viel> leichter verständlich werden, wenn ich sie auf (endliche)> Automaten abbilde.
Mir persönlich geht es eher so:
Diejenigen Aspekte von Programmiersprachen, für die es mir gelingt, sie
auf endliche Automaten abzubilden, verstehe ich auch ohne diese.
Deswegen hat es mich zunächst etwas überrascht, dass das bei dir anders
ist. Aber da hat wohl jeder seine eigene Denkweise, mit der er am besten
klar kommt, was ja vollkommen in Ordnung ist.
> Das Verständnis fällt mir SO viel leichter, dass ich> mich ernsthaft frage, warum die übliche Darstellung> auf eine so hirnrissig komplizierte Weise erfolgt.
Es könnte sein, dass es relativ wenig Leute gibt, die in diesem
Zusammenhang in Automaten denken. Deswegen gibt es ebenso wenige, die
dir etwas in deiner Sprache bzw. Denkweise erklären können.
>> Im Gegensatz zu Assembler und Ur-Fortran zeichnen sich>> moderne Sprachen aber durch weit mehr als nur die von>> ihnen unterstützten Ablaufstrukturen aus, als da wären:>>>> - Datentypen (numerisch, textuell, primitiv, zusammengesetzt,>> ...)>>>> - Typsysteme (stark, schwach, statisch, dynamisch, flach,>> hierarchisch, ...)>>>> - Möglichkeiten der Metaprogrammierung (Lisp-Makros,>> C++-Templates, ...)>>>> - u.v.m.>> "If it's not broken, don't fix it.">> Warum sollte ich Dinge umdeuten, mit denen ich in der> traditionellen Formulierung keine Verständnisprobleme> habe?
Jetzt verstehe ich gar nichts mehr :)
Wenn du nicht nur die Ablaufstrukturen verstanden hast, sondern auch
abstraktere Dinge wie die oben genannten, dann bist du ja fast schon auf
einer Ebene mit Wilhelm, und ich frage mich, was du denn noch nicht
verstanden hast. Vielleicht nennst du mal ein konkretes Beispiel, dann
können wir darüber diskutieren, mit welchen Hilfsmitteln man das am
besten erklären kann.
>> Ich habe deswegen lange nach einem besseren Ersatz für>> diese Maschinchen gesucht und schließlich auch gefunden:>>>> Mathematische Modelle>> Ich verstehe die Worte, nicht aber ihren Sinn: Ein Automat> IST doch (auch bzw. primär) ein mathematisches Modell --> nämlich ein Quintupel (X, Y, Z, f, g) mit bestimmten Eigen-> schaften.
Es ist ein mathematisches Modell, das zur Beschreibung bestimmter
Sachvehalte sehr gut taugt, für andere weniger gut und für wieder andere
überhaupt nicht.
> Nur hat dieses mathematische Modell den großen Vorzug, dass> ich sehr einfache elektronische Realisierungen für wenige> Cent bei der eingetragenen Kauffrau in Sande kaufen kann.
Du baust doch deine Automaten zur Erklärung von Programmieraspekten doch
nicht etwa in realer Elektronik auf? =8o
> Und ein weiterer Vorzug: Mir als E-Techniker ist das Modell> des endlichen Automaten vertraut -- also warum sollte ich> dieses Wissen nicht in Anschlag bringen, wenn es möglich> ist?
Wenn sie dir weiterhelfen, dann ist das in Ordnung. Mir (und
offensichtlich auch Wilhelm) helfen sie nicht weiter. Das ist für mich
ebenfalls in Ordnung, solange ich einen anderen Weg finde, etwas zu
verstehen :)
>> Endgültig die Augen aufgegangen sind mir, als ich begann,>> mich mit funktionaler Programmierung zu beschäftigen. In>> der reinen FP gibt es weder Abläufe noch Zustände, weswegen>> die Vorstellung von Maschinchen schon per se zu nichts>> führen kann.>> Ich bin... verwirrt.
Ich anfangs auch ;-)
> Wahrscheinlich missverstehe ich Deine Intention gründlich,> aber was ist Automatentheorie für Dich? Sowas wie die> Backförmchen für die Kindergartenkinder? Cargo-Mathematik> (--> Cargo-Kult) für Debile (=Elektrotechniker)?
Nein, überhaupt nicht. Ich benutze Automatentheorie durchaus, bspw. als
Hilfsmittel für den Entwurf von Digitalschaltungen. Automaten ohne die
Theorie setze ich manchmal als Entwurfsmuster in der Softwareentwicklung
ein.
> Ich weiss immer noch nicht, worauf Du mit der funktionalen> Programmierung hinauswillst.
Sie hat bei mir dazu geführt, bei der Softwareentwicklung weniger in
Schritt-für-Schritt-Abläufen, sondern mehr in mathematischen Funktionen
zu denken. Das heißt aber nicht, dass ich das "Schrittdenken" komplett
aufgegeben habe, aber ich beschränke es auf diejenigen Anwendungen, die
zu deren Natur es gut passt.
Beispiele:
- Eine Waschmaschinensteuerung schaltet schrittweise, abhängig von der
Zeit und von Sensorinformationen verschiedene Aktoren (Ventile, Pumpen
Trommelantrieb) ein und aus. Dafür ist das Schrittdenken und die
Formalisierung mit Automaten sehr gut geignet.
- Ein Sortieralgorithmus wird zwar vom Prozessor ebenfalls schrittweise
ausgeführt, von der Natur der Sache ist er aber eine mathematische
Funktion, deren Argument eine unsortierte, und deren Funktionswert die
sortierte Liste ist. Einen solchen Algorithmus mittels Automaten zu
beschreiben oder seine Ausführung in einem Debugger Schritt für
Schritt mitzuverfolgen, ist viel Arbeit und bringt für mich keinerlei
Nutzen.
> Die Sache ist faszinierend, ja -- unter anderem deshalb,> weil sie (genau wie die Deutung durch endliche Automaten)> ohne "Algorithmen" und die dadurch entstehenden "parasitären"> Zustände auskommt.> Vielleicht mache ich einen Fehler, aber ich sehe noch nicht,> wie mir die FP z.B. im Kontext der OOP helfen sollte.
So richtig gesehen habe ich das auch erst, als ich es gemacht habe. So
wie einer, der in der OOP zu Hause ist, auch gewöhnliche C-Programme
anders strukturieren wird, als einer, der von klassischem Basic kommt,
wird der C-Code von einem FPler noch einmal anders aussehen. In beiden
Fällen wird der resultierende C-Code an Verständlichkeit, Wartbarkeit
und Eleganz gewinnen.
Dass FP (zwar langsam, aber stetig) zu einem Trend wird, zeigt sich u.a.
darin, dass immer mehr Mainstream-Programmiersprachen (wie bspw. Python,
C# und seit einigen Jahren auch C++), prozedurale, objektorientierte und
funktionale Elemente in sich vereinen. Da sie dem Programmierer kein
bestimmtes Paradigma aufzwingen, ist mit ihnen ein sanfter Einstig in
die jeweiligen Paradigmen möglich.
Yalu X. schrieb:> Dass FP (zwar langsam, aber stetig) zu einem Trend wird, zeigt sich u.a.> darin, dass immer mehr Mainstream-Programmiersprachen (wie bspw. Python,> C# und seit einigen Jahren auch C++), prozedurale, objektorientierte und> funktionale Elemente in sich vereinen.
Und als Zusatz bzw. als das ganz Besondere (meiner Meinung nach) die
generische Programmierung, die sich wunderbar mit FP zusammenfügt. Ich
gebe zu, über die syntaktische Ausgestaltung bei C++ kann man geteilter
Meinung sein ;-) Durch Gewohnheit stört es mich nicht mehr.
> Da sie dem Programmierer kein> bestimmtes Paradigma aufzwingen, ist mit ihnen ein sanfter Einstig in> die jeweiligen Paradigmen möglich.
Und das sehe ich als die ganz große Stärke gerade von C++ an. Dadurch
kann man m.E. eine sehr große Expressivität im Code erreichen.
Dr. Sommer schrieb:> Klar. Aber die meisten nutzen, wie in Java, für alles int. Man sollte> wissen wann es sinnvoll ist und wann nicht ist.
Toll finde ich die Programmierer, die für eine Masse oder für ein
Volumen int verwenden (in C oder C++).
:-(
Mark B. schrieb:> Dr. Sommer schrieb:>> Klar. Aber die meisten nutzen, wie in Java, für alles int. Man sollte>> wissen wann es sinnvoll ist und wann nicht ist.>> Toll finde ich die Programmierer, die für eine Masse oder für ein> Volumen int verwenden (in C oder C++).
Ach, die Diskussion führe ich hier doch regelmäßig! Alles ist ein int,
und wenn nicht, dann ein String.
Markus F. schrieb:> Dr. Sommer schrieb:>> ... Strings die 0-Bytes enthalten...>> das ist für C-Programmierer ein Oxymoron.
Im Gegentum: Ein C-String, der am Ende kein NUL enthält, ist kaputt.
Also ist's eher eine Tautologie.
Alexander T. schrieb:> Im Gegentum: Ein C-String, der am Ende kein NUL enthält, ist kaputt.> Also ist's eher eine Tautologie
Und was ist NUL? Hoffentlich nicht NULL?
Ersetzt einfach "String" durch Byte-Array, dann passt es wieder. Oft
genug hat man Byte-Arrays die 0-Bytes enthalten können.
Lustig wird sowas:
1
std::stringfileName=getUserInput();
2
if(fileName=="geheim.txt")
3
Error("Permission denied");
4
fopen(fileName.c_str(),"r");
Wenn der User jetzt "geheim.txt\0bla" eingibt, greift die Sicherheits
Prüfung nicht, aber fopen sieht nur "geheim.txt"... Wer ist hier schuld?
Sowas ähnliches ist/war eine Sucherheitslücke in PHP.
Wilhelm M. schrieb:> Yalu X. schrieb:>>> Dass FP (zwar langsam, aber stetig) zu einem Trend wird, zeigt sich u.a.>> darin, dass immer mehr Mainstream-Programmiersprachen (wie bspw. Python,>> C# und seit einigen Jahren auch C++), prozedurale, objektorientierte und>> funktionale Elemente in sich vereinen.>> Und als Zusatz bzw. als das ganz Besondere (meiner Meinung nach) die> generische Programmierung, die sich wunderbar mit FP zusammenfügt. Ich> gebe zu, über die syntaktische Ausgestaltung bei C++ kann man geteilter> Meinung sein ;-)
Am besten ist es, wenn man die Generizität für jede Funktion sozusagen
gratis mit dazu bekommt, ohne dass man dazu eine spezielle Syntax
bemühen muss. Haskell und F# zeigen, wie's geht.
Eine Funktion, die die Summe einer Zahlenfolge berechnet, könnte in
Haskell bspw. so definiert werden:
1
mySum = foldl' (+) 0
foldl' ist dabei eine Bibliotheksfunktion, (+) die Funktion, die auf die
Elemente der Folge angewandt werden soll, und 0 der Initialwert für
die Aufsummierung.
Der Aufruf
1
mySum [1, 2, 5]
liefert das Resultat 8. Die Funktion erlaubt dabei beliebige faltbare
Argumente (List, Array, Set usw.) mit beliebigen numerischen Elementen
(Integer, Rational, Double, Complex Double usw.).
So leicht kann das Schreiben von wiederverwendbarem Code gehen :)
Dr. Sommer schrieb:> Lustig wird sowas:std::string fileName = getUserInput();> if(fileName == "geheim.txt")> Error ("Permission denied");> fopen (fileName.c_str (), "r");Wenn der User jetzt "geheim.txt\0bla"> eingibt, greift die Sicherheits> Prüfung nicht, aber fopen sieht nur "geheim.txt"... Wer ist hier schuld?> Sowas ähnliches ist/war eine Sucherheitslücke in PHP.
Mit purem C wäre das nicht passiert.
Der Murks liegt also bei getUserInput() und der Sicherheitsprüfung, für
die die Konstrukteure von std::string verantwortlich sind.
> Wenn der User jetzt "geheim.txt\0bla" eingibt, greift die Sicherheits> Prüfung nicht, aber fopen sieht nur "geheim.txt"... Wer ist hier schuld?> Sowas ähnliches ist/war eine Sucherheitslücke in PHP.
Man mischt ja auch nicht C Code mit C++ Code. Das sollte man nur machen,
wenn es gar nicht anders geht.
Dr. Sommer schrieb:> Statt int würde ich aber auch lieber int_least16_t schreiben, hat die> gleiche Bedeutung aber es zeigt klarer was man haben will.
int_fast16_t :)
int_least16_t würde ggf. auf Kosten von Rechenzeit (Bitmaskierung)
verlangen, dass es möglichst 16 Bit sind, dürfen nur dann mehr sein,
wenn die Architektur gar nicht mit 16-Bit-Einheiten umgehen kann.
Zur ursprünglichen Frage:
Mark W. schrieb:> schreibt Ihr auch gelegentlich mal Code, nur um Zeilen zu sparen?
Nein, nie.
Mark W. schrieb:> Oder geht das gar nicht?
Ja!
Erst die Aufgabe analysieren und dafür großzügig Zeit nehmen, dann das
Programm (gilt auch für Hardware) entwickeln und siehe da, man spart
insgesamt gesehen Zeit!
Keiner N. schrieb:> Man mischt ja auch nicht C Code mit C++ Code. Das sollte man nur machen,> wenn es gar nicht anders geht.
Leider sind die meisten Kernel in C geschrieben, und syscalls wie open
nutzen 0-terminierte Strings, auch wenn man sie direkt aus C++ aus
aufruft.
Jobst Q. schrieb:> Mit purem C wäre das nicht passiert.
Mit purem C++ auch nicht. Leider ist POSIX C-orientiert...
Jobst Q. schrieb:> für die die Konstrukteure von std::string verantwortlich sind.
Die Entwickler von std::string können wohl kaum was für diese Prüfung.
Man sollte wohl vor der Prüfung eventuelle 0-Bytes suchen... Aber wer
denkt schon an sowas.
Keiner N. schrieb:> Man mischt ja auch nicht C Code mit C++ Code. Das sollte man nur machen,> wenn es gar nicht anders geht.
C++ ist eine Erweiterung von C. Das ist ja auch der Vorteil gegenüber
anderen objektorientierten Sprachen. Also sollte es kompatibel mit C
sein.
Eine Neudefinition von String von einer Zeichenfolge, die mit dem
Null-Byte abgeschlossen wird, zu einem beliebigen Byte-Array ist ein
schwerwiegender Konstruktionsfehler.
Dr. Sommer schrieb:> Die Entwickler von std::string können wohl kaum was für diese Prüfung.> Man sollte wohl vor der Prüfung eventuelle 0-Bytes suchen... Aber wer> denkt schon an sowas.
Ich wollte gerade schreiben, dass die Prüfung auf '\0'-Zeichen innerhalb
des Dateinamens Aufgabe von [i][o]fstream::open(string &, ...) wäre,
denn genau hier geschieht die Umwandlung eines std::string-Dateinamens
in einen POSIX-, d.h. C-Dateinamen, und der Nutzer solcher High-Level-
Bibliotheksfunktionen sollte sich nicht darum kümmern müssen, ob sein
Betriebssystem POSIX-konform ist oder nicht.
Allerdings hat mich das ISO-Dokument eines Besseren belehrt:
Daraus geht hervor, dass der Dateiname am ersten '\0'-Zeichen unabhängig
vom Betriebssystem immer abgeschnitten wird und sogar werden muss. Wer
darauf reinfällt, hat halt vorher nicht genau genug nachgelesen ;-)
Vor C++11 gab es die open()-Variante mit dem std::string-Dateinamen noch
nicht, weswegen der Programmierer die c_str()-Konvertierung selber
hinschreiben musste, und somit eher auf das Problem aufmerksam wurde.
Die mit C++11 eingeführte Falle hätte man anständigerweise entschärfen
können, indem man in open() eine Prüfung auf '\0'-Zeichen eingebaut
hätte. Man hat es nicht getan, was wieder einmal bestätigt, dass die
Programmiererei kein Ponyhof ist, sondern nur der des Lesens Mächtige
erfolgreich sein kann ;-)
Yalu X. schrieb:> Eine Funktion, die die Summe einer Zahlenfolge berechnet, könnte in> Haskell bspw. so definiert werden:>>>
1
> mySum = foldl' (+) 0
2
>
>> foldl' ist dabei eine Bibliotheksfunktion, (+) die Funktion, die auf die> Elemente der Folge angewandt werden soll, und 0 der Initialwert für> die Aufsummierung.>> Der Aufruf>>>
1
> mySum [1, 2, 5]
2
>
>> liefert das Resultat 8. Die Funktion erlaubt dabei beliebige faltbare> Argumente (List, Array, Set usw.) mit beliebigen numerischen Elementen> (Integer, Rational, Double, Complex Double usw.).>> So leicht kann das Schreiben von wiederverwendbarem Code gehen :)
In C++:
Hallo,
mh schrieb:> Es ist allerdings nicht sinnvoll den kompletten Inhalt eines C++ und> eines OOP Lehrbuch in ein einzelnes Buch zu packen, denn niemand möchte> für Grundlangen ein 3000 Seiten 200€ Buch haben.
Ja, das ist richtig. Aber das Buch "Einführung in die Programmierung mit
C++" von Bjarne Stroustrup hat z.B. 1224 Seiten und trotzdem gibt es
keinen Platz für einen Überblick über die Konzepte, die hinter C++
stehen.
Dafür findet man im Kapitel 1 unter 1.5 "Computer sind allgegenwärtig"
eine _9_-seitige Aufstellung über Lebensbereiche, in denen Computer eine
wichtige Rolle spielen (das angeeignete Wissen wird dann mit Frage wie
"Wo spielt Software eine wichtige Rolle?. Nennen Sie einige Beispiele"
abgefragt. Mal ehrlich: was soll das?). Wenn für "sowas" Platz ist, dann
sollte es doch ein leichtes sein, auf 20-30 Seiten die Ideen, die hinter
C++ stehen zu beschreiben.
> Und was würde man dann mit den ganzen anderen Themen wie> prozeduale, funktionale und generische Programmierung machen? Alles in> ein Buch packen?
Da stellt sich die Frage was die Aufgabe eines
Programmiersprachenlehrbuches ist. Wenn die Darstellung der Konzepte
nicht dazu gehört, reicht ja eigentlich auch die Sprachreferenz der
aktuellen Version.
> Es müssen also immer mehrere Bücher benutzt werden.
Darauf wird es wohl hinauslaufen. Das erinnert mich allerdings an eine
Aussage eines Lehrers bezüglich des Lernens von Fremdsprachen. Er war
der Meinung, das man (europäische) Sprachen viel einfacher erlernen
könnte wenn man vorher Latein gelernt hätte. Da ist sicherlich auch was
dran, aber wenn jemand nur Französisch lernen will, kann man ja nicht
sagen "dann mach erst mal das große Latinum, danach ist Französisch ganz
einfach".
Vielleicht hast du aber recht und es geht wirklich nicht anders.
Allerdings stellt sich dann die Frage ob die momentan aktuellen
Programmiersprachenkonzepte wirklich sinnvoll sind. In Anbetracht der
der immer größer werdenden Wichtigkeit Software erstellen zu können,
kann man nicht erwarten das jeder zukünftige Programmierer über intimste
Informatikkenntnisse verfügt.
rhf
Roland F. schrieb:> Ja, das ist richtig. Aber das Buch "Einführung in die Programmierung mit> C++" von Bjarne Stroustrup hat z.B. 1224 Seiten und trotzdem gibt es> keinen Platz für einen Überblick über die Konzepte, die hinter C++> stehen.> Dafür findet man im Kapitel 1 unter 1.5 "Computer sind allgegenwärtig"> eine _9_-seitige Aufstellung über Lebensbereiche, in denen Computer eine> wichtige Rolle spielen (das angeeignete Wissen wird dann mit Frage wie> "Wo spielt Software eine wichtige Rolle?. Nennen Sie einige Beispiele"> abgefragt. Mal ehrlich: was soll das?).
Das ist natürlich unverständlich. Allerdings ist das Buch wohl auch
einfach hauptsächlich für Studenten und Dozenten geschrieben. Sieht für
mich jedenfalls so aus.
Roland F. schrieb:> Wenn für "sowas" Platz ist, dann> sollte es doch ein leichtes sein, auf 20-30 Seiten die Ideen, die hinter> C++ stehen zu beschreiben.
Das wird nicht funktionieren, einfach weil C++ eine Multiparadigma
Sprache ist. Da braucht es dann schon ein paar Seiten mehr, um alle zu
behandeln.
Roland F. schrieb:> Vielleicht hast du aber recht und es geht wirklich nicht anders.> Allerdings stellt sich dann die Frage ob die momentan aktuellen> Programmiersprachenkonzepte wirklich sinnvoll sind. In Anbetracht der> der immer größer werdenden Wichtigkeit Software erstellen zu können,> kann man nicht erwarten das jeder zukünftige Programmierer über intimste> Informatikkenntnisse verfügt.
Die Konzepte sind völlig in Ordnung. Aber wenn man zu viel auf einmal
lernen will, wird man wahrscheinlich daran scheitern. Man muss sich halt
fragen, ob es sinnvoll ist gleichzeitig das Programmieren zu lernen,
eine solche mächtige Programmiersprache wie C++ und dann noch ein
Paradigma wie OOP. Das ist einfach zu viel.
Deshalb würde ich nie und nimmer C++ bei Anfängern für die Lehre
einsetzen. Das ist eine Sprache, genauso wie C, die ganz klar die
erfahrenen Nutzer ansprechen will und auf Anfänger keine Rücksicht
nimmt.
Bei uns im Studium gab es uns die Informatiker und dann die
Wirtschaftsinformatiker. Wir haben mit C und C++ angefangen, die haben
ausschließlich Java gemacht. Und wer konnte insgesamt besser mit dem
Programmieren zurecht (mal diejenigen ausgenommen, die sowie schon
Programmieren konnten)? Tatsächlich die Wirtschaftsinformatiker, weil
ihnen die Sprache weniger Steine in den Weg gelegt hatte. Bei uns hatten
die Studenten schon mit C zu kämpfen (Zeiger, Speicherverwaltung,
nullterminierte Strings etc.), bei C++ war dann erst recht die Hölle
los. Auch ist mir aufgefallen, dass die Wirt.Inf. OOP sehr schnell intus
hatten. Erstens kannten die gar nichts anderes und zweitens ist das
ganze Thema in Java viel verständlicher (oder die Autoren davon können
es besser erklären).
Also mein Ratschlag: wer OOP lernen will, sollte einen weiten Bogen um
C++ machen und lieber C# oder Java dafür hernehmen. Es ist wirklich viel
einfacher. Danach kann man sich mit C++ befassen. Ich habe das selber so
gemacht und bin damit sehr gut gefahren, heute ist C++ meine
Lieblingssprache.
Dr. Sommer schrieb:> Die Entwickler von std::string können wohl kaum was für diese Prüfung.> Man sollte wohl vor der Prüfung eventuelle 0-Bytes suchen... Aber wer> denkt schon an sowas.
Der Murks fängt doch schon damit an, dass es überhaupt möglich ist ein
Null-Byte inmitten eines Strings einzugeben. Die Funktion getUserInput()
in deinem Beispiel kenne ich nicht und weiß daher auch nicht,ob die
Entwickler von std::string dafür verantwortlich sind.
Aber spätestens beim Vergleich mit dem überladenen Operator == hätten
sie dafür sorgen können, dass ihre Strings mit den üblichen C-Strings
kompatibel sind.
Bei der Entwicklung einer neuen Sprache wäre es egal, ob sie einen
String als beliebiges Bytearray definieren. Aber als Erweiterung von C
ist diese Inkompatibilität nicht zu verantworten.
Jobst Q. schrieb:> Die Funktion getUserInput()> in deinem Beispiel kenne ich nicht und weiß daher auch nicht,ob die> Entwickler von std::string dafür verantwortlich sind.
Die hab ich mir ausgedacht als Platzhalter für irgendeine Art von
Eingabe. Könnte z.B. über ein Netzwerk kommen.
BMP-Dateien enthalten z.B. Nullbytes. Wenn man die in einen std::string
einliest möchte man die erhalten. Wenn man also eine Eingabe/Protokoll
hat welches allgemein Binär-Daten überträgt, und es auch für Texte
nutzt, werden 0-Bytes mit übernommen. Dies ist z.B. bei HTTP-Formularen
der Fall; hier könnte ein Angreifer 0-Bytes mit senden. 0-Bytes in HTTP
komplett auszuschließen würde aber das Hochladen von BMP-Dateien
verhindern.
Die 0-Bytes sind auch kein Problem, bis man ein solches Byte-Array an
eine C/POSIX-Funktion übergibt.
Jobst Q. schrieb:> Aber spätestens beim Vergleich mit dem überladenen Operator == hätten> sie dafür sorgen können, dass ihre Strings mit den üblichen C-Strings> kompatibel sind.
Du meinst, es soll immer nur bis zum 0-Byte verglichen werden? Dann wäre
also std::string("foo\0bar") == "foo" wahr, aber std::string("foo\0bar")
== std::string("foo") falsch? Auch nicht sehr schön.
Jobst Q. schrieb:> Aber als Erweiterung von C> ist diese Inkompatibilität nicht zu verantworten.
std::string ist keine Erweiterung von "const char*" und somit von
C-Strings!!! std::string ist ein Datentyp für Zeichen-Arrays inklusive
0-Bytes, wobei ein Zeichen char, wchar, char32_t usw sein kann. Wenn man
unvorsichtigerweise c_str () aufruft und die Länge nicht mit
verarbeitet, nutzt man es halt falsch.
C-Strings funktionieren in C++ noch genauso, aber std::string ist eben
kein Wrapper für C-Strings.
Dr. Sommer schrieb:> Jobst Q. schrieb:>> Aber spätestens beim Vergleich mit dem überladenen Operator == hätten>> sie dafür sorgen können, dass ihre Strings mit den üblichen C-Strings>> kompatibel sind.> Du meinst, es soll immer nur bis zum 0-Byte verglichen werden? Dann wäre> also std::string("foo\0bar") == "foo" wahr, aber std::string("foo\0bar")> == std::string("foo") falsch? Auch nicht sehr schön.
Der Ctor von std::string interpretiert den C-String auch richtig. Also
std::string("foo\0bar") hat die Länge 3, denn "foo\0bar" ist ein
C-String der Länge 3 (per Konvention).
Einen String aus einem std::byte Array zu konstruieren geht nicht.
Der Fehler liegt ggf. schon in dem Netzwerkbeispiel darin, die Bytes vom
Netzwerk als char zu deklarieren, was sie ja nicht sind. Es sind Bytes.
Wilhelm M. schrieb:> Der Ctor von std::string interpretiert den C-String auch richtig. Also> std::string("foo\0bar") hat die Länge 3, denn "foo\0bar" ist ein> C-String der Länge 3 (per Konvention).
Achja, ich hatte irgendwie in Erinnerung dass die dem template-Trick
nutzen um die tatsächliche Länge zu erhalten... Ok, wenn man 0-Bytes
übergibt muss man die Länge angeben:
1
std::string("foo\0bar",7);
Wilhelm M. schrieb:> die BYtes vom> Netzwerk als char zu deklarieren, was sie ja nicht sind. Es sind Bytes.
Okay, wie hat man dann Bytes vom Netzwerk interpretiert bevor es
std::byte gab? byte ist ja auch nur als enum vom typ unsigned char
definiert. char darf definitiv 0 werden.
In Anbetracht der Tatsache dass die read/write -Funktionen von
istream/ostream "char*" akzeptieren hätte ich jetzt gedacht, dass man
char-Arrays, und damit auch std::string, sehr wohl zum Speichern von
Netzwerkdaten nutzen kann.
PS: Das User-Defined Literal "s" für std::string übernimmt 0-Bytes
korrekt:
1
#include<cstdio>
2
#include<string>
3
#include<iostream>
4
5
intmain()
6
{
7
usingnamespacestd::string_literals;
8
9
std::strings1="abc\0\0def";
10
std::strings2="abc\0\0def"s;
11
std::cout<<"s1: "<<s1.size()<<" \""<<s1<<"\"\n";
12
std::cout<<"s2: "<<s2.size()<<" \""<<s2<<"\"\n";
13
std::puts(s2.c_str());
14
std::fwrite(s2.data(),1,s2.size(),stdout);
15
std::puts("");
16
}
Ausgabe:
1
s1: 3 "abc"
2
s2: 8 "abc^@def"
3
abc
4
abc^@def
http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s
Der << Operator gibt den ganzen String aus, auch nach dem 0-Byte, weil
das eine "richtige" C++-Ausgabe ist welche eben die Länge auswertet.
puts geht nur bis zum 0-Byte, aber wenn man an fwrite die Länge übergibt
wird alles ausgegeben. Die 0-Bytes werden entsprechend dem Terminal gar
nicht oder irgendwie umschrieben ausgegeben (hier: ^@).
Dr. Sommer schrieb:> Wilhelm M. schrieb:>> Der Ctor von std::string interpretiert den C-String auch richtig. Also>> std::string("foo\0bar") hat die Länge 3, denn "foo\0bar" ist ein>> C-String der Länge 3 (per Konvention).>> Achja, ich hatte irgendwie in Erinnerung dass die dem template-Trick> nutzen um die tatsächliche Länge zu erhalten... Ok, wenn man 0-Bytes> übergibt muss man die Länge angeben:>
1
std::string("foo\0bar",7);
Ja, denn der C-String endet per Definitionem am Sentinel. Deswegen macht
der Typw.-ctor von std::string das auch korrekt.
> Wilhelm M. schrieb:>> die BYtes vom>> Netzwerk als char zu deklarieren, was sie ja nicht sind. Es sind Bytes.> Okay, wie hat man dann Bytes vom Netzwerk interpretiert bevor es> std::byte gab?
Konnte man ja machen seit es scoped enums gibt (C++11).
> byte ist ja auch nur als enum vom typ unsigned char> definiert.
Aber eben nich implizit konvertierbar in einen arithmetischen Typ
(char).
> char darf definitiv 0 werden.
Ja klar.
> In Anbetracht der Tatsache dass die read/write -Funktionen von> istream/ostream "char*" akzeptieren hätte ich jetzt gedacht, dass man> char-Arrays, und damit auch std::string, sehr wohl zum Speichern von> Netzwerkdaten nutzen kann.
Das ist doch nur ein C-Krücke, für ein Byte ein char zu nehmen. In C
muss man das so machen schlechterdings.
Dr. Sommer schrieb:> PS: Das User-Defined Literal "s" für std::string übernimmt 0-Bytes> korrekt:
Beide sind korrekt (s.o.): d.h. sie interpretieren den Quelldatentyp
richtig.
Wilhelm M. schrieb:> Das ist doch nur ein C-Krücke, für ein Byte ein char zu nehmen. In C> muss man das so machen schlechterdings.
Und wie macht man es in C++03? In C++17 arbeiten die read/write
Funktionen immer noch mit "char*".
Und was willst du eigentlich sagen? Dass man in dem Code-Snippet kein
std::string hätte verwenden dürfen, sondern std::byte? Wie wäre das in
C++03 gegangen? Dass man mit strcmp hätte vergleichen müssen?
Dr. Sommer schrieb:> Wilhelm M. schrieb:>> Das ist doch nur ein C-Krücke, für ein Byte ein char zu nehmen. In C>> muss man das so machen schlechterdings.>> Und wie macht man es in C++03?
Das war vor 15 Jahren, das interessiert mich wirklich nicht mehr.
struct byte {...};
> In C++17 arbeiten die read/write> Funktionen immer noch mit "char*".
Nein, mit void*.
std::fwrite ist ein namespace-aware wrapper für POSIX-fwrite, mehr
nicht.
> Und was willst du eigentlich sagen? Dass man in dem Code-Snippet kein> std::string hätte verwenden dürfen, sondern std::byte?
Wenn man einen Protokollbuffer mit binären, nicht-numerischen Daten hat,
dann wäre das ein std::array<std::byte, ...>, oder ein
std::vector<std::byte>, aber kein std::string.
> Wie wäre das in> C++03 gegangen?
Ja, aber da mache ich mir 15-Jahre später keine Gedanken mehr drüber.
> Dass man mit strcmp hätte vergleichen müssen?
Das vergleicht wieder nur C-Strings ... mit der (impliziten) Annahme,
dass die übergebenen Zeiger auf eine Folge (mindestens eins) Zeichen des
Typs const char zeigen, und dass diese Folge hoffentlich (keiner weiß
es) mit '\0' abgeschlossen ist. Falls nicht ... ok wir kennen die Story.
Sowas ist einfach nur Murks.
Dr. Sommer schrieb:> Wilhelm M. schrieb:>> Der Ctor von std::string interpretiert den C-String auch richtig. Also>> std::string("foo\0bar") hat die Länge 3, denn "foo\0bar" ist ein>> C-String der Länge 3 (per Konvention).>> Achja, ich hatte irgendwie in Erinnerung dass die dem template-Trick> nutzen um die tatsächliche Länge zu erhalten...
Ja, sowas hatte ich hier mal gepostet, damit man C-Strings (bspw. für
AVR) automatisch in bestimmte Sections (flash) legen kann. Dazu hatte
ich dann ein UDL-Op definiert: "abc"_pgm ist dann im Flash. Man kann
auch das getrost N-mal im Code verwenden, es wird nur einmal ins flash
gepackt.
Wilhelm M. schrieb:> Das war vor 15 Jahren, das interessiert mich wirklich nicht mehr.
Also keine Erklärung. Top.
Wilhelm M. schrieb:> Nein, mit void*.http://en.cppreference.com/w/cpp/io/basic_istream/read
Also hier steht char_type und das ist char bei std::ifstream.
Wilhelm M. schrieb:> aber kein std::string.
Wer sagt das? Und warum kann std::string dann problemlos damit umgehen?
Das o.g. Problem existiert nur bei der Nutzung als C-String.
Wilhelm M. schrieb:> Ja, sowas hatte ich hier mal gepostet
Daher kenn ich das nicht...
Dr. Sommer schrieb:> BMP-Dateien enthalten z.B. Nullbytes. Wenn man die in einen std::string> einliest möchte man die erhalten.
Was soll das für einen Sinn haben, eine Binärdatei in einen String
einzulesen?
> Wenn man also eine Eingabe/Protokoll> hat welches allgemein Binär-Daten überträgt, und es auch für Texte> nutzt, werden 0-Bytes mit übernommen. Dies ist z.B. bei HTTP-Formularen> der Fall; hier könnte ein Angreifer 0-Bytes mit senden. 0-Bytes in HTTP> komplett auszuschließen würde aber das Hochladen von BMP-Dateien> verhindern.
HTTP heißt Hypertext Transfer Protokoll. Es geht also um Texte. 0-Bytes
haben in Texten aber nichts zu suchen.
Um Binärdateien zu übertragen, werden sie meines Wissens mit Base64 oder
ähnlichem in Textdateien umgewandelt.
> Die 0-Bytes sind auch kein Problem, bis man ein solches Byte-Array an> eine C/POSIX-Funktion übergibt.
Sie sind auch in purem C kein Problem, wenn man die mem-Funktionen
verwendet. Der Fehler ist, die Byte-Arrays String zu nennen.
Dr. Sommer schrieb:> Wilhelm M. schrieb:>> Das war vor 15 Jahren, das interessiert mich wirklich nicht mehr.>> Also keine Erklärung. Top.
Lies genau: steht oben.
>> Wilhelm M. schrieb:>> Nein, mit void*.>> http://en.cppreference.com/w/cpp/io/basic_istream/read> Also hier steht char_type und das ist char bei std::ifstream.
Du hast oben aber std::fwrite() benutzt.
>> Wilhelm M. schrieb:>> aber kein std::string.>> Wer sagt das? Und warum kann std::string dann problemlos damit umgehen?
Wenn Du die Protokollintegrität sicherstellen kannst und Du wirklich nur
Zeichen überträgt, kannst Du es. Aber das wolltest Du ja nicht. Dein
Beispiel zielt auf andere Szenarien ab. Und hier ist das Empfangene erst
mal nur eine Folge von Bytes. Um es als eine Menge von Strings zu
interpretieren, brauchst Du dann eben einen (robusten) Parser. Der
filtert dann solche Sachen aus.
Dr. Sommer schrieb:> Leider sind die meisten Kernel in C geschrieben, und syscalls wie open> nutzen 0-terminierte Strings, auch wenn man sie direkt aus C++ aus> aufruft.
Ehrlich mal, POSIX hat genau zwei „verbotene“ Zeichen in Dateinamen,
das ist das Nullbyte und der Schrägstrich.
Vergleich' das mal mit anderen Betriebssystemen …
Ich hatte das mal für das EA eDIPTFT43-A benötigt, daß Arrays \0
beinhalten. Man kann sie als Strings definieren, aber natürlich nicht
mit Stringfunktionen ausgeben.
Ich hab das mit einen Macro gelöst, was per sizeof die Länge ermittelt.
Da an Strings immer ein 0-Byte angehängt wird, mußte ich noch 1
abziehen:
1
#define TFT_FKT(x) tft_wr( sizeof(x) - 1, x, 1 )
2
uint8_ttft_wr(uint8_tlen,uint8_t*dat,boolflash);// write to GLCD from SRAM or Flash
Wilhelm M. schrieb:> Mmh ...> void init(uint8_t* s) {> TFT_FKT(s);> }>> int main() {> init(INIT);> }
So geht's nicht, aber so, wie Peter geschrieben hat, schon.
Yalu X. schrieb:> Wilhelm M. schrieb:>> Mmh ...>> void init(uint8_t* s) {>> TFT_FKT(s);>> }>>>> int main() {>> init(INIT);>> }>> So geht's nicht, aber so, wie Peter geschrieben hat, schon.
Das ist mir schon klar: es ist DER Standardfehler. Deswegen sollte man
den sizeof()-Operator nicht dort benutzen, wo ein Array-Bezeichner zu
einem Zeiger zerfällt.
Wilhelm M. schrieb:> Deswegen sollte man den sizeof()-Operator nicht dort benutzen, wo ein> Array-Bezeichner zu einem Zeiger zerfällt.
Ich glaube, dessen ist sich Peter durchaus bewusst.
Deswegen übergibt er INIT ja auch nicht per Funktionsargument an
tft_init, sondern greift direkt darauf zu.
Yalu X. schrieb:> Wilhelm M. schrieb:>> Deswegen sollte man den sizeof()-Operator nicht dort benutzen, wo ein>> Array-Bezeichner zu einem Zeiger zerfällt.>> Ich glaube, dessen ist sich Peter durchaus bewusst.
Ihm mag das ja klar sein. Trotzdem fällt damit dieses Macro in die
Kategorie "Leicht falsch zu benutzen".
> Deswegen übergibt er INIT ja auch nicht per Funktionsargument an> tft_init, sondern greift direkt darauf zu.
Du siehst aber, wie schnell man den Fehler machen kann. Vor allem etwas
"unbedarfte" Anwender, die sich über dieses function-like Macro keine
gedanken machen. So etwas sollte heute nicht mehr möglich sein!
Wilhelm M. schrieb:> Trotzdem fällt damit dieses Macro in die Kategorie "Leicht falsch zu> benutzen".
Genau darum schreibt man ja Makros auch GROSS. Damit ist klar, dass
es ein Makro ist und eben keine Funktion, und dass man sich um dessen
Randbedingungen Gedanken machen muss, wenn man ihn benutzt.
Klar könnte man das in C++ alles viel schöner und eleganter schreiben.
Das hilft dir aber gar nichts, wenn du sowas in einem Projekt brauchst,
das über x Jahre mehrere hunderttausend Codezeilen akkumuliert hat, und
für das dir kein Kunde den Aufwand bezahlen würde, es ohne grundlegende
Erweiterung der Funktionalität nur der Eleganz und Schönheit wegen von
C in eine andere Sprache umzuschreiben.
Wilhelm M. schrieb:> Trotzdem fällt damit dieses Macro in die Kategorie "Leicht falsch zu> benutzen".
Fällt nicht das komplette C/C++ in diese Kategorie? ;-)
SCNR
Jörg W. schrieb:> Wilhelm M. schrieb:>> Trotzdem fällt damit dieses Macro in die Kategorie "Leicht falsch zu>> benutzen".>> Genau darum schreibt man ja Makros auch GROSS.
Was aber für den Präprozessor / Compiler unerheblich ist.
> Damit ist klar, dass> es ein Makro ist und eben keine Funktion, und dass man sich um dessen> Randbedingungen Gedanken machen muss, wenn man ihn benutzt.
Wenn sich alle Programmierer immer alle Gedanken machen würde, gäbe es
keine Bugs. Dem scheint aber nicht so zu sein ;-) Es ist besser, wenn
der Code bei falscher Verwendung der Schnittstelle nicht compiliert.
> Klar könnte man das in C++ alles viel schöner und eleganter schreiben.
Du kannst meine Gedanken lesen ;-)
Es wäre schöner, eleganter, sicherer und vermutlich effizienter gewesen.
> Das hilft dir aber gar nichts, wenn du sowas in einem Projekt brauchst,> das über x Jahre mehrere hunderttausend Codezeilen akkumuliert hat, und> für das dir kein Kunde den Aufwand bezahlen würde, es ohne grundlegende> Erweiterung der Funktionalität nur der Eleganz und Schönheit wegen von> C in eine andere Sprache umzuschreiben.
Das wollte ich damit auch gar nicht bezwecken. Ich kenne so etwas zur
Genüge.
Aber: wenn man so etwas (m.E. Murks) immer wieder hier postet, wird sich
an der Situation leider nichts ändern. Man muss zumindest deutlich
hervorgehoben werden. Was ich damit getan habe.
Yalu X. schrieb:> Wilhelm M. schrieb:>> Trotzdem fällt damit dieses Macro in die Kategorie "Leicht falsch zu>> benutzen".>> Fällt nicht das komplette C/C++ in diese Kategorie? ;-)
Das will ich gar nicht in Gänze bestreiten.
Allerdings sehe ich einen wesentlichen Unterschied:
In C kann man es leider nicht wirklich besser machen, in C++ hat man die
Möglichkeiten. Und gute Library-API-Designer nutzen diese Möglichkeiten.
Jörg W. schrieb:> Klar könnte man das in C++ alles viel schöner und eleganter schreiben.Das Beispiel braucht kein C++ um einigermassen wasserdicht zu werden.
Statt das sizeof() ins Makro zu schreiben eine entsprechende Konstante
definiert:
1
#define TFT_FKT(x) tft_wr(INIT_SIZE - 1, x, 1 )
2
staticconstsize_tINIT_SIZE=sizeof(INIT);
die und das Array hinter "static" versteckt, das Ganze in eine separate
Übersetzungseinheit, nur noch die Funktion nach aussen sichtbar und
schon ist das wesentlich ungefährlicher.
Markus F. schrieb:> Jörg W. schrieb:>> Klar könnte man das in C++ alles viel schöner und eleganter schreiben.>> Das Beispiel braucht kein C++ um einigermassen wasserdicht zu werden.>> Statt das sizeof() ins Makro zu schreiben eine entsprechende Konstante> definiert:>>
1
>#defineTFT_FKT(x)tft_wr(INIT_SIZE-1,x,1)
2
>staticconstsize_tINIT_SIZE=sizeof(INIT);
3
>
>> die und das Array hinter "static" versteckt, das Ganze in eine separate> Übersetzungseinheit, nur noch die Funktion nach aussen sichtbar und> schon ist das wesentlich ungefährlicher.
Ok, wenn das Macro weg ist, habe ich sicher kein Problem mehr damit ;-)
Wenn die Signatur von tft_wr() so bleibt, habe ich aber nichts gewonnen.
Das Macro versuchte gerade, die Fehlermöglichkeiten der Schnittstelle zu
eliminieren, was aber nicht funktioniert. Jetzt haben wir es wieder mit
den zwei "zusammenhanglosen" Parametern zu tun ... oh, es sind sogar
drei Parameter, die eine semantische Einheit bilden.
Peter D. schrieb:> prog_uint8_t INIT[] => "\x1bTC\0" // text cursor off> "\x1b""DO\2" // rotate 180°> "\x1b""FD\x8\x1" // display color> "\x1b""FZ\x8\x1" // text color> "\x1b""DL" // display clear> "\x1b""YZ\x0" // no delay> "\x1b""YH\x64" // light on> ;
wo ist da eigentlich der Vorteil zu plain C?
Wilhelm M. schrieb:> Aber: wenn man so etwas (m.E. Murks) immer wieder hier postet, wird sich> an der Situation leider nichts ändern.
Es wird bestimmt ein riesen Geschütz in C++ geben, mit dem man das viel
eleganter erschlagen kann. Nur muß man das erst finden und auch
verstehen.
Ich wollte auch verdeutlichen, daß man Strings und Arrays nicht einfach
in einen Topf werfen kann. Für Arrays funktioniert strlen nicht mehr und
man muß sich eine andere Methode ausdenken, um die Länge zu ermitteln.
Peter D. schrieb:> Es wird bestimmt ein riesen Geschütz in C++ geben, mit dem man das viel> eleganter erschlagen kann. Nur muß man das erst finden und auch> verstehen.
Das "Geschütz" nennt sich dort einfach "Objekt" … man definiert sich
eine Klasse, die intern außer dem Bytehaufen auch noch die Länge als
Eigenschaft hat. Durch einen passenden Konstruktor kann man beim
Erzeugen eines Objekts (also einer Instanz dieser Klasse) dann einen
ganz normalen String als Initialisierer angeben.
Sehr wahrscheinlich gibt es sogar so eine Klasse schon irgendwie
irgendwo, andererseits ist das so einfach, dass man es als C++-Einstieg
durchaus auch als Fingerübung benutzen kann, das mal selbst zu zimmern.
Wobei textCursorOff () usw die einzelnen Befehle erzeugen, und combine
daraus ein Array macht. Kann ich aber gerade nicht vollständig
ausführen. Wäre so dann auch hübsch:
Peter D. schrieb:> Wilhelm M. schrieb:>> Aber: wenn man so etwas (m.E. Murks) immer wieder hier postet, wird sich>> an der Situation leider nichts ändern.>> Es wird bestimmt ein riesen Geschütz in C++ geben, mit dem man das viel> eleganter erschlagen kann. Nur muß man das erst finden und auch> verstehen.
So schlimm ist das ja eigentlich gar nicht. Allerdings ist der
Ausgangspunkt ,eine Kommandosequenz sei ein String, nicht gut.
Ein Kommando für dieses Display sind zwei Codes (Ascii-Zeichen) und dann
eine Payload. Die Kommandos können im Binär- oder Ascii-Modus gesendet
werden. Im Binär-Modus haben wir ein anderes Startbyte als im
Ascii-Modus, wo auch noch Trennzeichen gesendet werden sowie alles
dezimal codiert wird.
Daraus kann man erkennen, dass das Startbyte nicht zum Command gehört
und auch die Trennzeichen etc. erst durch die Realisierung des
Übertragungsmodus bestimmt werden.
Man könnte ein Kommando also einfach als Folge von Bytes darstellen:
1
std::array<std::byte,Size>command;
Allerdings ist das einzig Variable an einem festen Kommando die Payload,
deswegen kann man die zwei Codes des Kommandos auch gleich in den Typ
einbeziehen (und noch Bytes sparen):
Ob man das Kommando als std::array oder eigenes Template realisiert, man
hat es auf jedenfall mit unterschiedlichen Typen der Kommandos zu tun.
Deswegen kann man für eine Kommandosequenz keine homogenen Container
benutzen wie std::array<typ-der-commandos, anzahl>, sondern man braucht
einen heterogenen Container, etwa std::tuple:
Dabei ist natürlich lästig, die Länge der Payload explizit angeben zu
müssen und auch die explizite Typwandlung nach std::byte ist zwar gut,
aber sehr verbose.
Das geht dann mit einer Factory-Funktion einfacher:
1
template<charF,charS,typename...VV>
2
constexprautocommand(VV...vv){
3
returnCommand<F,S,sizeof...(VV)>(vv...);
4
}
Die Funktionen leitet die Länge ab und erzeugt die passenden
Parameterierung.
Also:
(Ein user-defined deduction-guide geht hier nicht wegen der expl.
Instanziierung durch die Kommando-Codes).
Jetzt ist noch das std::byte etwas lästig, dafür bieten sich
UDL-Operatoren an:
1
constexprstd::byteoperator""_B(charc){
2
returnstd::byte(c);
3
}
Nun kann man schreiben:
1
constexprautoinit_sequence=std::make_tuple(
2
command<'T','C'>(0_B,1_B),
3
command<'D','O'>(2_B)
4
);
Um die Sequenz ausgeben zu können:
1
template<typenameCommands>
2
voidtft_write(constCommands&commands){
3
std::apply([](auto...c){
4
// Assertion, das c den richtigen Typ hat, oder familiar-template syntax für diese lambda-expr (c++20)
5
// Ausgabe auf Ascii- oder Binär-Interface
6
},commands);
7
}
Dies geht dann mit jedem Container, der die Anforderungen von
std::apply<>() erfüllt.
Die Art des Inferfaces entscheidet dann über Start-Byte, Trennzeichen,
Prüfsumme, etc...
Wenn man sich noch etwas mehr Mühe gibt, kann man auch statisch prüfen,
ob die Kombination der beiden Ascii-Codes Sinn macht und ob die Payload
dazu passt. Wie gesagt: statisch. Bei einem Fehler würde das Programm
nicht compilieren! Man muss also zur Laufzeit dahingehend ggf. nichts
debuggen.
heißen, damit das String-Ende-'\0' nicht mit ausgegeben wird.
Im Prinzip gefällt mir deine Lösung gut, aber hundertprozentig
anfängertauglich ist auch sie nicht unbedingt:
Wilhelm kritisierte an Peters Lösung, dass damit folgendes nicht möglich
ist:
1
voidinit(uint8_t*s){
2
TFT_FKT(s);
3
}
4
5
intmain(){
6
init(INIT);
7
}
Möchte man das mit deiner Methode realisieren, muss auch init eine
Template-Funktion sein:
1
template<typenameT,std::size_tN>
2
inlinevoidinit(T(&arr)[N]){
3
tft_wr(arr);
4
// weiterer Initialisierungcode
5
// ...
6
}
Wird init mehrfach mit jeweils unterschiedlich langen Init-Strings
genutzt, wird dessen Code durch den Compiler jeweils dupliziert, was auf
den Mikrocontrollern, auf den sich Peter herumtreibt, insbesondere bei
sehr umfangreichem init-Code nicht erwünscht ist.
Wenn man sich des Problems bewusst ist, kann man es leicht umgehen. Wenn
der Programmierer aber dazu in der Lage ist, ist er kein blutiger
Anfänger mehr, so dass für ihn auch das von Wilhelm angeführte Problem
mit dem zum Zeiger zerfallenden Array keines darstellt.
Deswegen stellt sich für mich generell die Frage, wieviel Aufwand man in
zusätzlichem Quellcode man stecken sollte, um damit Programmierfehler zu
vermeiden, die nur mit sehr geringer Wahrscheinlichkeit passieren (in
dem Moment, wo man beginnt, nach einer Alternativlösung zu suchen, hat
man die Gefahr ja schon erkannt und wird deswegen nicht mehr in die
Falle tappen).
Dabei denke ich jetzt weniger an deine Lösung (die ja sehr kompakt und
relativ schnell hingeschrieben ist), sondern an Wilhelms Vorschläge, die
sich oft über zig Codezeilen erstrecken.
@Wilhelm:
Betrachte das, was ich hier schreibe, bitte nicht als generelle Kritik
an deiner Art und Weise zu programmieren. Ich kann aus deinen Beispielen
viel lernen, und ich werde viele deiner Vorschläge künftig auch in
meinem eigenen Code umsetzen, nur nicht unbedingt in so einfachen
Kontexten, wo ich befürchte, dass der Aufwand schnell mal den Nutzen
übersteigt.
Yalu X. schrieb:> Wird init mehrfach mit jeweils unterschiedlich langen Init-Strings> genutzt, wird dessen Code durch den Compiler jeweils dupliziert, was auf> den Mikrocontrollern, auf den sich Peter herumtreibt, insbesondere bei> sehr umfangreichem init-Code nicht erwünscht ist.
Das ist zwar grundsätzlich richtig, allerdings ist der Effekt in der
Praxis vernachlässigbar bzw. geht im Rauschen unter. Der Grund dafür
ist, dass das Compilerfrontend den template-code i.A: besser optimieren
kann (s.u.).
> @Wilhelm:>> Betrachte das, was ich hier schreibe, bitte nicht als generelle Kritik> an deiner Art und Weise zu programmieren. Ich kann aus deinen Beispielen> viel lernen, und ich werde viele deiner Vorschläge künftig auch in> meinem eigenen Code umsetzen, nur nicht unbedingt in so einfachen> Kontexten, wo ich befürchte, dass der Aufwand schnell mal den Nutzen> übersteigt.
Das kann jeder gerne so halten, wie er möchte. Ich kann dazu nur sagen,
dass wir seit Jahren genau diese Strategie verfolgen und damit wirklich
sehr erfolgreich sind. Der Code, den ich hier ab und zu mal poste bzw.
die Kommentare, die ich dazu abgebe, sind dann immer aus Sicht des
Library-Guys, also des Generalisten. Das kann man auch oben sehen, denn
es ist nun ganz leicht, einen Protokolladapter für das Ascii-Protokoll
oder einen für das Binärprotokoll des Displays dazwischen zu schieben,
was natürlich bei der alles-ist-ein-String-Variante nicht geht, die die
Grenzen zwischen den Kommandos und ihren Bestandteilen sind ja nicht
(statisch) sichtbar.
Grundsätzlich haben wir folgende Ziele:
* Header-Only Template Code
* Möglichst viele Fehler zur Compilezeit
* Permanentes Code-Refreshment auf Bibliotheksebene (full C++ feature
set)
Zwar ist AVR nicht unsere Zielplattform sondern SAM/ARM, aber auch dort
bleibt der allseits postulierte Code-Bloat aus.
Das wesentliche ist dem Compiler so viel statische Information wie
möglich mitzugeben bzw. die Datentypen optimal zu wählen: Werte sind
bedeutungslos, Datentypen sind alles. Die Vorteile dieser Strategie
scheinen evtl. Nachteile (etwa durch Mehrfachinstanziierungen)
auszugleichen, das zeigen jedenfalls exemplarische Untersuchungen, die
wir mal gemacht haben.
Wilhelm M. schrieb:>> Wird init mehrfach mit jeweils unterschiedlich langen Init-Strings>> genutzt, wird dessen Code durch den Compiler jeweils dupliziert, was auf>> den Mikrocontrollern, auf den sich Peter herumtreibt, insbesondere bei>> sehr umfangreichem init-Code nicht erwünscht ist.>> Das ist zwar grundsätzlich richtig, allerdings ist der Effekt in der> Praxis vernachlässigbar bzw. geht im Rauschen unter. Der Grund dafür> ist, dass das Compilerfrontend den template-code i.A: besser optimieren> kann (s.u.).
Das mag manchmal zutreffen, im gerade diskutieren Fall wird aber an den
Templates überhaupt nichts optimiert.
Ich habe Dr. Sommers Beispiel auf 4 Init-Strings erweitert, die
nacheinander alle durch einen Aufruf von init an das Display geschickt
werden. Um die stattfindende Code-Duplikation zu verdeutlichen, habe ich
in init ein paar Rechenoperationen angefügt.
test.cpp:
1
#include<stddef.h>
2
#include<stdint.h>
3
4
uint8_tINIT1[]="\x1b""A";
5
uint8_tINIT2[]="\x1b""BB";
6
uint8_tINIT3[]="\x1b""CCC";
7
uint8_tINIT4[]="\x1b""DDDD";
8
9
voidtft_wr(uint8_t*arr,size_tlength);
10
11
template<typenameT,size_tN>
12
inlinevoidtft_wr(T(&arr)[N]){
13
tft_wr(arr,N);
14
}
15
16
volatileuint32_ta,b,c,d;
17
18
template<typenameT,size_tN>
19
inlinevoidinit(T(&arr)[N]){
20
tft_wr(arr);
21
22
// relativ viel zusätzlicher Code
23
a=b+c;d=a+b;c=d+a;b=c+d;
24
a=b+c;d=a+b;c=d+a;b=c+d;
25
}
26
27
intmain(){
28
init(INIT1);
29
init(INIT2);
30
init(INIT3);
31
init(INIT4);
32
}
Diesen Code habe ich für einen AVR kompiliert und mir die Größe der
erzeugten Objektdatei ausgeben lassen:
1
avr-gcc -mmcu=atmega8 -std=c++17 -Os -c test.cpp
2
avr-size test.o
Die Größe der text-Section ist mit einem einzelnen init-Aufruf
468 Bytes,
mit allen 4 Aufrufen
1854 Bytes,
also fast das Vierfache. Der Compiler erzeugt tatsächlich 4 Instanzen
der Template-Funktion, deren Assembler-Code jeweils 132 Instruktionen
lang ist und sich nur in einer einzigen Instruktion von den anderen
Instanzen unterscheidet.
Diesen schon sehr deutlichen Zuwachs der Codegröße kann man in diesem
Beispiel vermeiden, indem man den von den Template-Parametern
unabhängigen Teil der init-Funktion in eine separate Funktion auslagert.
Dazu muss man sich aber erst einmal des Problems bewusst werden und darf
nicht zu sehr auf die Optimierungsfähigkeiten des Compilers hoffen.
Yalu X. schrieb:> Die Größe der text-Section ist mit einem einzelnen init-Aufruf>> 468 Bytes,>> mit allen 4 Aufrufen>> 1854 Bytes,>> also fast das Vierfache. Der Compiler erzeugt tatsächlich 4 Instanzen> der Template-Funktion, deren Assembler-Code jeweils 132 Instruktionen> lang ist und sich nur in einer einzigen Instruktion von den anderen> Instanzen unterscheidet.
Auch wenn init static, also "wirklich nur hier gebraucht", ist bzw. LTO
benutzt wird?
Gerade getestet:
- gcc8.1
- "static" vor allen Funktionen (außer Main) oder LTO,
- O3
-> 586 Bytes .text
> Diesen schon sehr deutlichen Zuwachs der Codegröße kann man in diesem> Beispiel vermeiden, indem man den von den Template-Parametern> unabhängigen Teil der init-Funktion in eine separate Funktion auslagert.> Dazu muss man sich aber erst einmal des Problems bewusst werden und darf> nicht zu sehr auf die Optimierungsfähigkeiten des Compilers hoffen.
Doch, darf man!
Man muß ihm nur die nötige Info mitgeben, z.B. daß Funktionen niemals
von außerhalb gerufen werden.
Oder eben über den"Trick" LTO, dann bekommt er das selber raus.
PS: einmal init -> 576 Bytes, ergo: kein Bloat!
Carl D. schrieb:> Auch wenn init static, also "wirklich nur hier gebraucht", ist bzw. LTO> benutzt wird?
Bei mir ändert sich die Codegröße dadurch nur marginal.
Carl D. schrieb:> - "static" vor allen Funktionen (außer Main) oder LTO,
Was machst du mit
1
voidtft_wr(uint8_t*arr,size_tlength);
?
Ich bin davon ausgegangen, dass das eine externe Bibliotheksfunktion
ist. Wenn du sie ebenfalls static machen möchtest, musst du natürlich
dafür sorgen, dass sie irgendetwas mit dem Argument length anstellt,
bspw. so:
1
staticvoidtft_wr(uint8_t*arr,size_tlength){
2
volatilesize_tdummy=length;
3
}
Sonst unterscheiden sich die 4 Template-Instanzen nicht voneinander und
können durch den Compiler zu einer einzigen zusammengefasst werden.
Carl D. schrieb:>> Dazu muss man sich aber erst einmal des Problems bewusst werden und darf>> nicht zu sehr auf die Optimierungsfähigkeiten des Compilers hoffen.> Doch, darf man!> Man muß ihm nur die nötige Info mitgeben, z.B. daß Funktionen niemals> von außerhalb gerufen werden.
Mal anders argumentiert: Die Größe des Arrays ist in dem einen Fall ein
Datum, mit dem ein Algorithmus arbeitet, in dem anderen Fall ein
Parameter des Algorithmus selbst.
und
kann man sicher so definieren, dass sie das selbe Ergebnis liefern. Aber
in dem einen Fall ist die 35 ein Argument einer Funktion die somit
allgemeiner anzuwenden ist.
Das wird bei den Beispielen hier schon dann deutlich, wenn man mal
versucht eine unbestimmte Menge von Kommandos aus einer Datei
einzulesen...
Yalu X. schrieb:> Ich habe Dr. Sommers Beispiel auf 4 Init-Strings erweitert, die> nacheinander alle durch einen Aufruf von init an das Display geschickt> werden. Um die stattfindende Code-Duplikation zu verdeutlichen, habe ich> in init ein paar Rechenoperationen angefügt.
Du hast ein Beispiel konstruiert(!), was natürlich eine starke
Vermehrung des Maschinencodes bewirkt. Dies ist allerdings durch die
volatile Qualifizierung im template entstanden. Dies entspricht
allerdings nicht der Praxis.
In der Praxis haben wir SFRs, die notwendigerweise volatile qualifiziert
sind, oder (ganz wenige) Datenstrukturen, die nebenläufig verwendet
werden, und deswegen volatile sind.
Jetzt komme ich mit einem etwas praxisrelevanteren Beispiel: wir wollen
die Daten der Arrays durch ein Protokoll laufen lassen und dann auf
irgendeiner Schnittstelle ausgeben. Die Schnittstelle ist hier einfach
mal als ein SFR dargestellt. Natürlich soll das ganze ein bisschen
modular sein: unterschiedliche Protokolle mit unterschiedlichen
Schnittstellen kombinierbar.
Variante A in C:
main.c:
Da bekomme ich für das Target atmega328:
C: 238 Bytes text, 7 Bytes bss
C++: 188 Bytes text, 7 Bytes bss
Wenn ich für die C-Variante LTO einschalte:
C: 198 Bytes text, 7 Bytes bss
Soweit zu Beispielen (frei nach Pipi Langstrumpf!).
Hinzu kommt m.E. der besser strukturierte und sicherere Code. Wenn man
das Beispiel erweitert auf:
1
usingspi1=Spi<0>;
2
usingspi2=Spi<1>;
3
usingp1=Protocol<A,spi1>;
4
usingp2=Protocol<A,spi2>;
5
6
std::array<std::byte,2>a1;
7
std::array<std::byte,4>a2;
8
std::array<std::byte,8>a3;
9
std::array<std::byte,16>a4;
10
11
intmain(){
12
p1::put(a1);
13
p1::put(a2);
14
p2::put(a3);
15
p2::put(a4);
16
}
bzw.:
1
voidspi1_put(uint8_tdata);
2
voidspi2_put(uint8_tdata);
3
4
uint8_ta1[2];
5
uint8_ta2[4];
6
uint8_ta3[8];
7
uint8_ta4[16];
8
9
intmain(){
10
protocol_A(a1,sizeof(a1),spi1_put);
11
protocol_A(a2,sizeof(a2),spi1_put);
12
protocol_A(a3,sizeof(a3),spi2_put);
13
protocol_A(a4,sizeof(a4),spi2_put);
14
}
so haben wir (mit LTO für C):
C: 272 Bytes text, 32 Bytes bss
C++: 224 Bytes text, 32 Bytes bss
Also hier sehen wir nichts von Code-Bloat, im Gegenteil.
Wilhelm M. schrieb:> Yalu X. schrieb:>>> Ich habe Dr. Sommers Beispiel auf 4 Init-Strings erweitert, die>> nacheinander alle durch einen Aufruf von init an das Display geschickt>> werden. Um die stattfindende Code-Duplikation zu verdeutlichen, habe ich>> in init ein paar Rechenoperationen angefügt.>> Du hast ein Beispiel konstruiert(!), was natürlich eine starke> Vermehrung des Maschinencodes bewirkt. Dies ist allerdings durch die> volatile Qualifizierung im template entstanden. Dies entspricht> allerdings nicht der Praxis.
Konstruiert ist nur dieser Teil als Beispiel für einen etwas größeren
Codeabschnitt:
1
volatileuint32_ta,b,c,d;
2
3
...
4
// relativ viel zusätzlicher Code
5
a=b+c;d=a+b;c=d+a;b=c+d;
6
a=b+c;d=a+b;c=d+a;b=c+d;
Ersetze ihn durch irgendwelchen sinnvollen, ähnlich großen Code, der
frei von volatiles ist, und du wirst feststellen, dass er immer noch für
jeden init-Aufruf dupliziert wird.
Wie ich oben geschrieben habe, kann das Problem dadurch behoben werden,
dass der gemeinsame, von den Template-Parameter unabhängige Code in eine
separate Funktion ausgelagert werden.
Fakt ist aber dass diese Optimierung durch den Programmierer geschehen
muss, der Compiler ist dazu (noch) nicht in der Lage.
> Jetzt komme ich mit einem etwas praxisrelevanteren Beispiel: wir wollen> die Daten der Arrays durch ein Protokoll laufen lassen und dann auf> irgendeiner Schnittstelle ausgeben.
Ich schrieb ja nicht, dass der Code-Bloat immer auftritt. In deinem
Beispiel tritt das Problem deswegen nicht in Erscheinung, weil die
put-Funktionen sehr klein sind. Sobald diese Funktionen etwas mehr tun
als nur ein paar Bytes zu kopieren, wirst du auch hier die
Codeduplizierung bemerken.
Yalu X. schrieb:> Ersetze ihn durch irgendwelchen sinnvollen, ähnlich großen Code, der> frei von volatiles ist, und du wirst feststellen, dass er immer noch für> jeden init-Aufruf dupliziert wird.
Das stimmt auf der einen Seite, auf der anderen Seite entstehen durch
den Template-Code größere Optimierungspotentiale (sowohl durch den
Compiler wie auch im Algorithmus selbst) wie oben schon gesagt.
Vielleicht wird es deutlich, warum in Summe kein Code-Bloat auftritt,
wenn wir unser Protokoll für längere Folgen erweitern und fügen eine
Summe hinzu: