Hi
ich arbeite zwar lange mit C, musste hier und da auch kleinere Projekte
mit C++ angehen.
sind diese ganzen Erweiterungen von c++11/14/17 weltbewegend und
verbreitet?
Auch im embedded Bereich?
Klaus
Klaus schrieb:> sind diese ganzen Erweiterungen von c++11/14/17 weltbewegend und> verbreitet? Auch im embedded Bereich?
Ja, ja, ja. Viele der Neuerungen sind für embedded sehr nützlich, wie
z.B. Vorberechnung via constexpr. Es gibt kaum einen Grund sich auf den
18 Jahre alten Sprachstandard C++03 zu beschränken.
Den Schritt zu c++11 würde ich schon weltbewegend bezeichnen.
Aber bei so einer unspezifischen Frage kann man auch einfach
ja/nein/vielleicht antworten ;)
Klaus schrieb:> Hi> ich arbeite zwar lange mit C, musste hier und da auch kleinere Projekte> mit C++ angehen.> sind diese ganzen Erweiterungen von c++11/14/17 weltbewegend und> verbreitet?
Definitiv.
> Auch im embedded Bereich?
Hmm, schwer zu sagen. Ich nutze sie dort. Kommt aber auch drauf an, was
der verfügbare Compiler kann. Manche sind bei solchen Änderungen ja
nicht gerade rasend schnell unterwegs, vor allem, wenn sie zertifiziert
sein müssen.
Klaus schrieb:> c++11/14/17
Inzwischen kannst du auch noch C++20 mit hinzunehmen.
Einige der Neuerungen sind sehr praktisch und erleichtern das
Programmieren, weswegen sich die Beschäftigung damit auf jeden Fall
lohnt.
Andere blähen IHMO die Sprache nur weiter auf und hätten genauso gut
weggelassen werden können. Aber das ist ein allgemeines Problem bei
Kommiteesprachen (nicht nur C++): Da will jeder Beteiligte auf Biegen
und Brechen seine supertolle Idee in den Standard einbringen, und wenn
der Vorschlag nicht völlig destruktiv ist, stimmen die anderen halt
irgendwann zu, damit der Standardisierungsprozess nicht zu sehr ins
Stocken gerät.
Yalu X. schrieb:> Andere blähen IHMO die Sprache nur weiter auf und hätten genauso gut> weggelassen werden können.
Was würdest du sagen bläht die Sprache nur auf?
Rolf M. schrieb:> Manche sind bei solchen Änderungen ja> nicht gerade rasend schnell unterwegs, vor allem, wenn sie zertifiziert> sein müssen.
Eben. Sicherheitsregel: "Never change a running system. Never run a
changed system" !
Hau wech den Scheiss schrieb:> Eben. Sicherheitsregel: "Never change a running system. Never run a> changed system" !
Nach dem Motto tut sich aber nie was, oder man müsste ständig komplett
neue Sprachen erfinden um Neuerungen umzusetzen. Es gibt auf der ganzen
Welt nicht genug Programmierer, um ständig alles in neue Sprachen neu zu
implementieren, wenn man die neuen Features nutzen will.
Yalu X. schrieb:> Andere blähen IHMO die Sprache nur weiter auf und hätten genauso gut> weggelassen werden können.
Andere finden diese Features gut. Um nicht völlig von anderen Sprachen
abgehängt zu werden, kann man dort etablierte Features übernehmen. C++
hat auch eine Daseinsberechtigung für neue Projekte, abseits der Pflege
existierender Systeme, und hier möchte man vielleicht von neuen Features
profitieren. Wer hat jetzt Recht?
Programmierer schrieb:> Hau wech den Scheiss schrieb:>> Sicherheitsregel: "Never change a running system. Never run a>> changed system" !>> Es gibt auf der ganzen> Welt nicht genug Programmierer, um ständig alles in neue Sprachen neu zu> implementieren, wenn man die neuen Features nutzen will.
Eben. Warum irgendwelche modischen Neuerungen durchdrücken, wenn es
weder die Manpower dafür gibt, noch irgendwelche Verbesserungen an der
Sicherheit aka Kundenzufriedenheit zu erwarten sind.
Hau wech den Scheiss schrieb:> Eben. Warum irgendwelche modischen Neuerungen durchdrücken, wenn es> weder die Manpower dafür gibt, noch irgendwelche Verbesserungen an der> Sicherheit aka Kundenzufriedenheit zu erwarten sind.
Dann, gib mal wenigstens ein Beispiel aus dem c++20 Standard
- das eine modische Neuerung und
- zuwenig Manpower (was auch immer du damit meinen magst) hat und
- keine Verbesserung an Sicherheit oder Kundenzufriedenheit erwarten
lässt.
Hau wech den Scheiss schrieb:> Eben. Warum irgendwelche modischen Neuerungen durchdrücken, wenn es> weder die Manpower dafür gibt, noch irgendwelche Verbesserungen an der> Sicherheit aka Kundenzufriedenheit zu erwarten sind.
Worauf bezieht sich das jetzt? Neue Sprachfeatures wie z.B. Lambdas
bedeuten einfachere und schnellere Entwicklung und Wartung, und dadurch
geringere Entwicklungskosten und billigere Endprodukte, und billig macht
Kunden zufrieden.
Programmierer schrieb:> Hau wech den Scheiss schrieb:>> Eben. Warum irgendwelche modischen Neuerungen durchdrücken, wenn es>> weder die Manpower dafür gibt, noch irgendwelche Verbesserungen an der>> Sicherheit aka Kundenzufriedenheit zu erwarten sind.>> Worauf bezieht sich das jetzt? Neue Sprachfeatures wie z.B. Lambdas> bedeuten einfachere und schnellere Entwicklung und Wartung, und dadurch> geringere Entwicklungskosten und billigere Endprodukte, und billig macht> Kunden zufrieden.
Es geht um Software-Qualifizierung also Sicherheitskritischer Bereich.
Das kann schon Automotive sein, und da will der Kunde sicher und
unbeschadet angekommen und zahlt dafür auch einen Aufschlag. Siehe
Volvo.
Die Software ist eben nicht nach der Entwicklung fertig, da schliesst
sich mindestens noch die verifikatiopn an.Und da bleibt man lieber bei
gut bewährter Software .
Und die billigste Software ist immer noch die, die man schon hatund
deren Schwachstellen man kennt.
Hau wech den Scheiss schrieb:> Es geht um Software-Qualifizierung also Sicherheitskritischer Bereich.
Seit wann?
Hau wech den Scheiss schrieb:> Und da bleibt man lieber bei> gut bewährter Software .
Warum?
Neue C++-Versionen bieten bessere Möglichkeiten zur typsicheren
(Meta-)Programmierung, damit kann man mehr Fehler direkt beim
Kompilieren erkennen, wodurch sich die Fehlerwahrscheinlichkeit wieder
reduziert.
Hau wech den Scheiss schrieb:> da schliesst> sich mindestens noch die verifikatiopn an.
Echte Verifikation wird in der Automobilindustrie nicht gemacht, da
praktisch unmöglich.
Leider sind die Toolchain-Anbieter im Embedded-Bereich seeeehr träge,
was das Implementieren der "neuen" C++-Standards angeht. C++11 ist bei
vielen schon das höchste der Gefühle.
Aber ja: C++ hat viele Features, die auch im Embedded-Bereich sehr
sinnvoll wären oder sind.
In Automotive und Co (alles was mit FuSi zu tun hat), braucht man
zertifizierte Komponenten, das schließt den Compiler, die Hardware, die
Toolchain mit ein. Ein zertifizierter C++11 (wenn man überhaupt das
Glück hat, C++ benutzen zu dürfen (!)) wird nicht mal eben durch einen
C++17 (falls es den überhaupt "schon" gibt) ersetzt. Das ist zu teuer
(denn man muss häufig dann mehrere Varianten parallel haben, um alte
builds reproduzieren zu können) und dabei ist die Entwicklungszeit
(Lambdas, constexpr etc) leider fast vollkommen egal - zumindest war es
das in den letzten Firmen, die ich von innen gesehen habe.
edit: Von Keil gibts beispielsweise gerade mal C++11:
https://developer.arm.com/tools-and-software/embedded/arm-compiler/safety
Programmierer schrieb:> Hau wech den Scheiss schrieb:>> Es geht um Software-Qualifizierung also Sicherheitskritischer Bereich.>> Seit wann?
Seit der Aspekt der Software-Zertifizierung in den Thread geworfen
wurde:
Beitrag "Re: c++ 11/14/17?"
Hau wech den Scheiss schrieb:
>> Und da bleibt man lieber bei>> gut bewährter Software .>Warum?
Naja, weil man davon ausgeht das sich Software die sich in der
Vergangenheit als Fehlerarm gezeigt hat, auch in Zukunft das selbe
Fehlerarme Verhalten zeigen wird. Software unterliegt keinem Verschleiß
und muss daher nicht permanent erneuert werden.
>Echte Verifikation wird in der Automobilindustrie nicht gemacht, da>praktisch unmöglich.
Klar, und ich bin der Kaiser von China.
Hau wech den Scheiss schrieb:>>Echte Verifikation wird in der Automobilindustrie nicht gemacht, da>>praktisch unmöglich.>> Klar, und ich bin der Kaiser von China.
Ich denke, da hat er Recht. Echte aka formale Verifikation ist bei
komplexen Zusammenhängen extremst aufwendig oder nahezu unmöglich.
mh schrieb:> Dann, gib mal wenigstens ein Beispiel aus dem c++20 Standard
...
> - zuwenig Manpower (was auch immer du damit meinen magst) hat
Es geht dabei nicht um den Standard selbst, sondern um die
Compiler-Entwickler, die das dann in ihren Produkten umsetzen müssen.
Programmierer schrieb:> Neue C++-Versionen bieten bessere Möglichkeiten zur typsicheren> (Meta-)Programmierung, damit kann man mehr Fehler direkt beim> Kompilieren erkennen, wodurch sich die Fehlerwahrscheinlichkeit wieder> reduziert.
Das basiert aber auf der Annahme, dass der Compiler selbst generell
keine Fehler hat. Als Entwickler der Software hat man allerdings nur auf
den Quellcode Einfluss, nicht aber auf den Compiler selbst.
Hau wech den Scheiss schrieb:> Hau wech den Scheiss schrieb:>>> Und da bleibt man lieber bei>>> gut bewährter Software .>>>Warum?>> Naja, weil man davon ausgeht das sich Software die sich in der> Vergangenheit als Fehlerarm gezeigt hat, auch in Zukunft das selbe> Fehlerarme Verhalten zeigen wird. Software unterliegt keinem Verschleiß> und muss daher nicht permanent erneuert werden.
Darüber hinaus kennt man bei länger verwendeter Software die bestehenden
Fehler, und ein Wechsel auf eine neue Software würde die Fehler durch
neue ersetzen, die man noch nicht kennt. Und bekannte Fehler sind immer
besser als unbekannte. Deshalb wird auch in der Raumfahrt gerne "gut
abgehangene" Hardware verwendet, also z.B. Prozessor-Typen, die es schon
sehr lange gibt. Neben der geringen Komplexität sind dort auch mehr von
den Fehlern bereits gefunden worden als bei neuerer Hardware.
>>Echte Verifikation wird in der Automobilindustrie nicht gemacht, da>>praktisch unmöglich.>> Klar, und ich bin der Kaiser von China.
Er meint mit "Verfikiation" vermutlich die Erbringung eines formalen
Beweises für die Korrektheit.
Jan K. schrieb:> Hau wech den Scheiss schrieb:>>>Echte Verifikation wird in der Automobilindustrie nicht gemacht, da>>>praktisch unmöglich.>>>> Klar, und ich bin der Kaiser von China.>> Ich denke, da hat er Recht. Echte aka formale Verifikation ist bei> komplexen Zusammenhängen extremst aufwendig oder nahezu unmöglich.
Nur wenn man das Design und den Entwicklungsprozess nicht auf
Verifikation hin auslegt. Schon mal was von Design for Testability
gehört? Oder Test Automatisition Equipment? Fehlerinjektion?
Also ich kenn da Automotive-Buden die haben mehrere Bladeracks und
HIL-Aufbauten im Serverraum stehen, die nichts anderes machen als die
Firmware Tagelang mit testpattern zu stressen. Hinzukommen die Tausenden
Testfahrzeuge mit Protokollrecordern, die mehrere MannJahrzehnte an
realen Szemarien aufzeichnen bevor der Automobilhersteller seine
Freigabe erteilt.
https://www.pcwelt.de/news/BMWs-autonome-Autos-1.500-TB-neue-Daten-pro-Tag-10564439.html
Ntürlich wird in der Automobilindustire verifiziert -so gut und
Vollständig es eben geht. Deshalb nimmt man ja auch unnötige Komplexität
aus dem Produkt/Entwicklungsprozess. beispielsweise die, durch Zulassung
neuer Code-Standards zwangsläufig entsteht. - "Never change a running
system"
Hau wech den Scheiss schrieb:> Nur wenn man das Design und den Entwicklungsprozess nicht auf> Verifikation hin auslegt. Schon mal was von Design for Testability> gehört? Oder Test Automatisition Equipment? Fehlerinjektion?
Testen hat nichts mit Verifikation zu tun. Verifikation bedeutet, einen
formalen mathematischen Beweis zu erbringen, dass die Software exakt der
Spezifikation entspricht. Und das ist bei komplexer Software ein
gewaltiger Aufwand. Um diesen zu vermeiden, testet man halt einfach
möglichst viele (trotzdem nur ein verschwindend geringer Anteil) Fälle
in der Hoffnung, dass die verbleibenden Fälle auch korrekt sind.
C++20 Software kann man genau so testen wie C89-Software.
Jan K. schrieb:> In Automotive und Co (alles was mit FuSi zu tun hat), braucht man> zertifizierte Komponenten, das schließt den Compiler, die Hardware, die> Toolchain mit ein.
Nur braucht das der größte Teil der Software in einem Auto gar nicht.
Und da zur Zeit jeder Kommentar über die deutsche Automobilindustrie in
etwas lautet "können alles, ausser Software", würde ich auf die
bisherigen Gepflogenheiten dort auch nicht allzuviel geben.
Ich bin mir ziemlich sicher, daß weder Google, noch Apple oder Tesla
sich mit Misratenen Normentwürfen herumschlagen. Die sitzen stattdessen
in den C++-Normungsgremien, und gehen damit vorwärts.
Oliver
Oliver S. schrieb:> Ich bin mir ziemlich sicher, daß weder Google, noch Apple oder Tesla> sich mit Misratenen Normentwürfen herumschlagen. Die sitzen stattdessen> in den C++-Normungsgremien, und gehen damit vorwärts.
Das stimmt vermutlich. Und glaub mir, ich bin über den langsamen
Fortschritt auch angenervt, bekomme es tagtäglich auf der Arbeit mit.
Möchte man aber Hardware/Module in einem Auto oder in der Industrie
unterbringen, muss häufig nach den erwarteten Normen entwickelt werden.
Macht man das nicht, bekommt man das Projekt nicht - ganz einfach. Und
ISO26262 und co kommen gerade erst richtig und schwappen von purem
Automotive in Richtung Transportation, Industrie, Baumaschinen etc.
@Hau wech den Scheiss (Gast), du kennst leider den Begriff formale
Verifikation nicht. Das hat nichts mit Testen zu tun. Natürlich wird
viel getestet und wer seine Software samt Drumherum nicht testbar
gestaltet, hat irgendwann grundsätzlich die A-Karte.
Klaus schrieb:> sind diese ganzen Erweiterungen von c++11/14/17 weltbewegend
ja
> und> verbreitet?
In diesem Forum stoßen sie regelmäßig auf Kritik ;-) Das scheint ein
gutes Zeichen zu sein.
> Auch im embedded Bereich?
Eigentlich gerade da.
Meine persönliche Hitliste im µC-Bereich (inkl. c++20) sind:
1) concepts: der Schlüssel zu compiletime-polymorphie und TMP
2) constexpr everywhere
3) lambda-expr. Verbesserungen (e.g. explicit template-lambda parameter)
4) stdlib: tuple<>, variant<>, bit_cast<>, etc. zusammen mit 2)
5) template-alias (using) und viele Kleinigkeiten vereinfachen die TMP
mh schrieb:> Yalu X. schrieb:>> Andere blähen IHMO die Sprache nur weiter auf und hätten genauso gut>> weggelassen werden können.>> Was würdest du sagen bläht die Sprache nur auf?
Zwei Beispiele, die mich besonders stören:
1. Die Uniform Initialization:
Zu den bereits bestehenden mehreren Möglichkeiten der Initialisierug
kommt nun noch eine weitere hinzu
https://xkcd.com/927/
beschreibt die Situation ganz treffend, wenn man dort "standards"
durch "initialization methods" ersetzt.
Nicht ganz so schlimm fände ich die Uniform Initialization, wenn sie
wenigstens die klassischen Initialisierungsmethoden komplett ersetzen
könnte, aber das tut sie nicht.
Dazu kommt noch, dass nun einige meinen, deren Verwendung auf die
Spitze treiben zu müssen, so dass dann Stilblüten wie diese
entstehen:
1
for(inti{};i<3;i++)
2
...
Das ist zwar legaler Code, aber was soll der Unfug?
Anfangs habe ich die Uniform Initialization selber verwendet, u.a. um
in meinem Code zu dokumentieren, dass ich mit der Zeit gehe und nicht
an alten Zöpfen hänge ;-) Mittlerweile ist mir das egal, weswegen ich
wieder zu den klassischen Initialisierungsmethoden zurückgekehrt bin.
Mich spricht auch deren Syntax mehr an.
2. Typsynonyme mit using als Alternative zu typedef:
Ich frage mich, was an der typedef-Syntax schlecht ist. Den einzigen
Mangel sehe ich darin, dass typedef nicht getemplatet werden kann,
ein Problem, das seit der Einführung der Templates in C++ (also schon
lange vor C++11) diskutiert wird, aber nie behoben wurde. Statt
einfach auch typedef-Templates zu erlauben, wurde die völlig neue
using-Syntax eingeführt. Wozu? Habe ich irgendwelche schwerwiegende
Gründe übersehen, warum das für typedef nicht möglich ist?
Es gibt noch ein paar weitere IHMO unsinnige neue Features, die ich aber
aus meinem Gesichtsfeld entschwunden sind, da sie auch von anderen kaum
genutzt werden. Sie machen damit lediglich das Standarddokument und die
Lehrbücher fett, stören aber wenigstens bei der täglichen Arbeit nicht.
Bitte nicht missverstehen: Meine Kritik bedeutet keineswegs, dass ich
zurück zu C++03 möchte, ganz im Gegenteil. C++11 und Nachfolger bringen
insgesamt mehr positive als negative Erweiterungen mit. Die für mich
wichtigsten positiven Punkte sind:
1. Range based Loops:
Endlich kann man über die Elemente eines Containers ohne dieses
lästige begin() und end() iterieren.
2. Lambda-Ausdrücke:
C++ war eine der letzten Sprachen, die das noch nicht hatte, deswegen
wurde es höchste Zeit, das nachzuliefern.
3. Neue Datentypen in Standardbibliothek
Tuple, Optional, verschiedene Sorten von Smart Pointers usw.
4: π
Ich hätte nicht geglaubt, dass das bisher GCC-spezifische M_PI noch
irgendwann in den Standard aufgenommen werden wird. Seit letzten
Dezember (C++20) ist es aber tatsächlich so weit: Es gibt jetzt u.a.
std::numbers::pi in <numbers>. Ich frage mich nur, warum das fast ein
halbes Jahrhundert gedauert hat.
5. Compilezeitberechnungen mit constexpr:
Wenn ich sehe, wie man solche Dinge früher mit Template-Hacks
hingedoktert hat (einige haben daraus eine regelrechte Wissenschaft
gemacht), ist diese Erweiterung ein wirklicher Segen.
6. Contraints und Concepts:
Endlich wird das leidige Problem mit dem Duck-Typing in Templates und
den damit verbundenen schwer interpretierbaren Fehlermeldungen etwas
entschärft. Diese Lösung ist zwar nicht besonders schön und bedarf
zusätzlicher Zuarbeit vonseiten des Template-Entwicklers, aber mehr
war unter Beibehaltung der Abwärtskompatibilität wohl nicht möglich.
7. Stark typisierte Enums
Ein weitere Schritt zu mehr Fehlererkennung durch den Compiler.
8. Type Inference:
Implementiert wurde zwar nur eine schwache Form davon, aber auch
diese ist oft sehr hilfreich, bspw. bei der Deklaration eines
Iterators zu einem gegebenen Container-Objekt.
9. Korrekte Unterscheidung zwischen doppelten Temnplate-Klammern und dem
>>-Operator
Früher musste bspw. bei std::vector<std::vector<int>> zwischen den
beiden ">" ein Leerzeichen eingefügt werden.
Das aus meiner Sicht größte Problem an C++ ist die Komplexität. Es gibt
alles und dann noch die kleine Schwester davon.
Im Ergebnis übersteigt die Komplexität der Sprache die Hirne der
Entwickler, die dann nur einen kleinen Teil der Möglichkeiten überhaupt
nutzen. Ohne einen übergeordneten Standard nutzt dann jeder noch einen
anderen Teil, was die Sprache für Menschen schlecht lesbar machen kann.
Kompatiblität ist schön und gut, aber im Drei-Jahres-Takt ausschließlich
neue Dinge hinzufügen macht das nicht gerade besser.
Das "es gibt mehr als eine gute Lösung" ist es, was Perl so nervig macht
und C++ geht aus meiner Sicht den gleichen Weg.
S. R. schrieb:>> Kompatiblität ist schön und gut, aber im Drei-Jahres-Takt ausschließlich> neue Dinge hinzufügen macht das nicht gerade besser.>> Das "es gibt mehr als eine gute Lösung" ist es, was Perl so nervig macht> und C++ geht aus meiner Sicht den gleichen Weg.
Es gibt aus gutem Grund mehrere Lösungen. Denn wenn wegen neuer Ideen
die alten Projekte nicht mehr übersetzbar sind, dann wird das wie bei
Python 2 vs 3, wo auch heute noch beides parallel installiert sein muß.
Wenn nun etwas, was bisher umständlich war, durch ein neues, eleganteres
Verfahren ersetzt werden kann, dann sollte da ein "endlich" zu hören
sein. Falls es es keine übergeordneten Gründe gibt, das komplizierte zu
behalten (Zertifizierung).
"Immer schon so gemacht" haben wir eben "auf den Bäumen sitzen".
Ausnahmen würde ich bei so Dingen machen wie "ich habe 'volatile' nicht
verstanden und plädiere dafür es abzuschaffen". Wenn sowas von Firmen
kommt, die eigentlich lieber ihre homebrew Sprachen verwenden, da kann
man über die wirklichen Gründe mutmaßen. Da ist Apple nicht anders als
MS.
Carl D. schrieb:> Es gibt aus gutem Grund mehrere Lösungen.
Das ist mir schon klar und ich kann auch das C++-Konsortium verstehen.
Ändert aber nichts daran, dass der enorme Sprachumfang allein schon
dafür sorgt, dass niemand die Sprache mehr vollständig überblicken kann.
Fällt z.B. immer dann auf, wenn bei den Vorträgen mal in die Runde
gefragt wird, welchen Datentyp (oder welche Fehlermeldung) ein
bestimmter Ausdruck jetzt erzeugt - und das selbst den Experten, die den
Standard schreiben, nicht klar ist.
Wilhelm M. schrieb:> Mir kommen echt die Tränen, dass Ihr Euch in so viele neue Dinge> einarbeiten müsst.
Du beherrschst sämtliche Features von C++20? :-)
Mark B. schrieb:> Du beherrschst sämtliche Features von C++20? :-)
Der schlaue Programmierer lernt sie bei Bedarf anstatt sich jedes Mal
über den bösen Fortschritt zu beklagen...
Mark B. schrieb:> Wilhelm M. schrieb:>> Mir kommen echt die Tränen, dass Ihr Euch in so viele neue Dinge>> einarbeiten müsst.>> Du beherrschst sämtliche Features von C++20? :-)
Die 2h, um einmal alle Änderungen zu überfliegen, sollte man haben. Den
Rest kann man machen, wenn man es braucht oder die Zeit hat.
Wilhelm M. schrieb:> Mir kommen echt die Tränen, dass Ihr Euch in so viele neue Dinge> einarbeiten müsst.
Hängt schlicht davon ab, ob man für das "sich in viele neue Dinge
einarbeiten" oder etwas anderes bezahlt wird, und ob man dafür eher eine
Stunde oder drei Monate braucht.
mh schrieb:> Die 2h, um einmal alle Änderungen zu überfliegen, sollte man haben.
Sicherlich, aber die Konsequenzen daraus sind nochmal eine ganz andere
Hausnummer.
S. R. schrieb:> Sicherlich, aber die Konsequenzen daraus sind nochmal eine ganz andere> Hausnummer.
Was sind denn die Konsequenzen "daraus"?
Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.
mh schrieb:> Was sind denn die Konsequenzen "daraus"?>> Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.
Nun ja, mit concepts, auto überall, constexpr lambdas, ranges, und was
da alles noch so an Kleinigkeiten dabei ist, sieht der Code doch schon
sehr anders aus als das, was man mit C++11 so gebastelt hat. Bis man das
in voller Konsequenz mal mental umgesetzt hat, dauerts schon länger als
nur zwei Stunden.
Aber new und delete gibts auch immer noch, wer will, kannn nach wie vor
"C mit Klassen"-Code schreiben.
Oliver
mh schrieb:> Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.
Die Konsequenz daraus ist, das du die Chance verschenkst deinen Code
(typ) sicherer zu machen ;-)
Oliver S. schrieb:> mh schrieb:>> Was sind denn die Konsequenzen "daraus"?>>>> Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.>> Nun ja, mit concepts, auto überall, constexpr lambdas, ranges, und was> da alles noch so an Kleinigkeiten dabei ist, sieht der Code doch schon> sehr anders aus als das, was man mit C++11 so gebastelt hat. Bis man das> in voller Konsequenz mal mental umgesetzt hat, dauerts schon länger als> nur zwei Stunden.
Es ging um C++20, also sind nur die Änderungen seit C++17 relevant. Und
wie gesagt:
mh schrieb:> Die 2h, um einmal alle Änderungen zu überfliegen, sollte man haben. Den> Rest kann man machen, wenn man es braucht oder die Zeit hat.
Niemand erwartet, dass du das alle C++20 Änderungen von heute auf morgen
perfekt benutzen kannst.
Hans-Georg L. schrieb:> mh schrieb:>> Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.>> Die Konsequenz daraus ist, das du die Chance verschenkst deinen Code> (typ) sicherer zu machen ;-)
Kannst du genauer erklären, wann ICH eine Chance verschenkt habe? Oder
was wolltest du mit dem Beitrag zum Ausdruck bringen?
mh schrieb:> Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.
Wenn man es nicht einsetzt, dann bleibt man aber bei C++03 stehen. Also:
Entweder lernt man die neuen Features, oder man benutzt sie halt nicht.
mh schrieb:> Es ging um C++20, also sind nur die Änderungen seit C++17 relevant.
Es ging um C++20 im Vergleich zu dem Stand vor C++11.
mh schrieb:> Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.
Es geht nicht darum, ob ich es einsetze, sondern ob jemand anderes das
in der gleichen Codebasis einsetzt, mit der ich arbeiten muss. Und
selbst wenn ich einsetze heißt das noch lange nicht, dass der Rest des
Teams damit arbeiten kann.
Oliver S. schrieb:> Nun ja, mit concepts, auto überall, constexpr lambdas, ranges, und was> da alles noch so an Kleinigkeiten dabei ist, sieht der Code doch schon> sehr anders aus als das, was man mit C++11 so gebastelt hat.
Schöne Zusammenfassung.
Genau das macht modernes C++20 effektiv zu einer völlig anderen
Programmiersprache als der, die ich vor garnicht so vielen Jahren mal
als "C++" kennengelernt habe.
Rolf M. schrieb:> mh schrieb:>> Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.>> Wenn man es nicht einsetzt, dann bleibt man aber bei C++03 stehen. Also:> Entweder lernt man die neuen Features, oder man benutzt sie halt nicht.
Warum erwähnst du jetzt C++03? Willst du wirklich aussagen, dass man
entweder alle neuen Feauters einsetzt, oder sich auf einen fast 20 Jahre
alten Standard beschränken muss? Es gibt nichts was da zwischen liegt?
Ich kann mir nicht vorstellen, dass du das wirklich sagen willst.
> mh schrieb:>> Es ging um C++20, also sind nur die Änderungen seit C++17 relevant.>> Es ging um C++20 im Vergleich zu dem Stand vor C++11.
Dann verfolge die Kette mal bis zu dem Betrag, aus dem dieser Satz von
mir stammt. Um es einfacher zu machen:
mh schrieb:> Mark B. schrieb:>> Wilhelm M. schrieb:>>> Mir kommen echt die Tränen, dass Ihr Euch in so viele neue Dinge>>> einarbeiten müsst.>>>> Du beherrschst sämtliche Features von C++20? :-)>> Die 2h, um einmal alle Änderungen zu überfliegen, sollte man haben. Den> Rest kann man machen, wenn man es braucht oder die Zeit hat.
Es ging also sehr wohl um C++20.
S. R. schrieb:> mh schrieb:>> Ich sehe Nichts, das große Konsequenzen hat, wenn es nicht einsetzt.>> Es geht nicht darum, ob ich es einsetze, sondern ob jemand anderes das> in der gleichen Codebasis einsetzt, mit der ich arbeiten muss. Und> selbst wenn ich einsetze heißt das noch lange nicht, dass der Rest des> Teams damit arbeiten kann.
Es ist jetzt also die Schuld des Standardkomitees, dass ihr euch im Team
nicht auf ein gemeinsames Werkzeug einigen könnt?
> Oliver S. schrieb:>> Nun ja, mit concepts, auto überall, constexpr lambdas, ranges, und was>> da alles noch so an Kleinigkeiten dabei ist, sieht der Code doch schon>> sehr anders aus als das, was man mit C++11 so gebastelt hat.>> Schöne Zusammenfassung.>> Genau das macht modernes C++20 effektiv zu einer völlig anderen> Programmiersprache als der, die ich vor garnicht so vielen Jahren mal> als "C++" kennengelernt habe.
C++11 oder C++20. Wo sind plötzlich C++14 und C++17 geblieben? Habt ihr
euch wirklich seit 6 Jahren nicht mehr weitergebildet? Dann kann es ja
kein besonders wichtiges Werkzeug sein.
mh schrieb:> Dann verfolge die Kette mal bis zu dem Betrag,> aus dem dieser Satz von mir stammt.
Der Thread handelt von den "ganzen Erweiterungen von C++11/14/17".
Die Beschränkung auf "die Unterschiede zwischen C++17 und C++20" kam
tatsächlich von dir, hat aber sonst niemanden interessiert. ;-)
S. R. schrieb:> mh schrieb:>> Dann verfolge die Kette mal bis zu dem Betrag,>> aus dem dieser Satz von mir stammt.>> Der Thread handelt von den "ganzen Erweiterungen von C++11/14/17".>> Die Beschränkung auf "die Unterschiede zwischen C++17 und C++20" kam> tatsächlich von dir, hat aber sonst niemanden interessiert. ;-)
Wenn Mark B. schreibt "Du beherrschst sämtliche Features von C++20",
kommt das also plötzlich von mir?
mh schrieb:> S. R. schrieb:>> mh schrieb:>>> Dann verfolge die Kette mal bis zu dem Betrag,>>> aus dem dieser Satz von mir stammt.>>>> Der Thread handelt von den "ganzen Erweiterungen von C++11/14/17".>>
So sehe ich das auch.
>> Die Beschränkung auf "die Unterschiede zwischen C++17 und C++20" kam>> tatsächlich von dir, hat aber sonst niemanden interessiert. ;-)>> Wenn Mark B. schreibt "Du beherrschst sämtliche Features von C++20",> kommt das also plötzlich von mir?
Es kam nicht von dir, aber du hast dich auf die Reduktion darauf
eingelassen.
Wenn man generisch programmiert ist es auf jeden Fall sinnvoll die C++20
Constraints und concepts sich anzuschauen.
Was wollen wir?
[] Wir wollen eine Programmiersprache, die sich nicht ändert, damit wir
unser Denken nicht ändern müssen.
[] Wir wollen eine Programmiersprache, die vollständig abwärtskompatibel
ist, damit der alte Code immmer noch compiliert werden kann, und ohne
neue Bugs läuft. Alte Bugs sollen erhalten bleiben.
[] Wir wollen ein Programmiersprache, die top-modern ist, und die
allerneuesten Features, die diskutiert werden, inkludiert.
[] Wir wollen eine Programmiersprache, die nicht aufgebläht ist, weil
regelmäßig alte Features entfernt werden.
[] Wir wollen eine Programmiersprache, die möglichst wenig Features hat,
damit sie leicht zu lernen ist.
[] Wir wollen eine Programmiersprache, die immer den schnellsten
Maschinen-Code und auch sonstwie den effizientesten Ressourcengebrauch
liefert.
[] Wir wollen ein Programmiersprache, dessen Syntax uns persönlich am
besten passt.
[] Wir wollen eine Programmiersprache, die sich nicht ändert, damit wir
nichts neues lernen müssen.
[] Wir wollen eine Programmiersprache, die nicht von einem Gremium
definiert wird, damit wir uns nicht engagieren müssen.
[] Wir wollen eine Programmiersprache, die wir erlernen können, ohne zu
lernen bzw. ihr Historie oder ihre grundlegenden Ideen zu verstehen.
[] ...
[] ...
Schaut aus, wie im richtigen Leben ;-)
[x] Wir wollen C89 ("ANSI-C") weil wir das im Studium lernen mussten und
zu faul sind irgendwas anderes zu lernen. Außerdem Simulink weil das so
schön bunt ist.
Im übrigen ist das hier Diskutierte eher ein Problem der "alten Säcke"
als der "jungen Hüpfer". Die Jungen kommen oft aus eine Script-Welt o.ä.
und sind "überglücklich" über die Möglichkeiten des "modernen C++". Die
Umständlichkeiten des "alten C++" erzählt man einmal, und dann lassen
sie die auch sofort gerne links liegen.
Also entweder gefällt mir ausnahmslos alles an C++, oder ich bin
lernfaul, alt oder sonst wie minderbemittelt. Ist das in etwa richtig
zusammengefasst?
Eumel schrieb:> Also entweder gefällt mir ausnahmslos alles an C++, oder ich bin> lernfaul, alt oder sonst wie minderbemittelt. Ist das in etwa richtig> zusammengefasst?
Wenn Du das darin liest, dann sicherlich ja ;-)
Wilhelm M. schrieb:> Im übrigen ist das hier Diskutierte eher ein Problem der "alten Säcke"> als der "jungen Hüpfer". Die Jungen kommen oft aus eine Script-Welt o.ä.> und sind "überglücklich" über die Möglichkeiten des "modernen C++". Die> Umständlichkeiten des "alten C++" erzählt man einmal, und dann lassen> sie die auch sofort gerne links liegen.
Ich bin so ein alter Sack, der mit programmieren angefangen hat als der
8080 Assembler noch vom Lochstreifen eingelesen wurde, mit "klassischem"
C++ später sein Geld verdient hat und schon ein Weilchen Rentner ist
;-).
Wenn du keine Erfahrung hast wie man ein System in wieder verwendbare
Klassen aufteilt nützen dir die tollsten Features einer Sprache nichts.
Ob Erfahrungen aus der Script Welt dabei helfen sei mal dahin gestellt.
Im Moment versuche ich meine C Programme für die STM32 MC auf C++ um zu
stellen und da sind Klassen eher unwichtig und die neuen Features sehr
willkommen. Allerdings unterstützt die STM Cube-IDE nur den gcc 9.3.1
und somit C++17 aber es lässt sich nur -std=c++14 einstellen. Diese
blöden Eclipse IDEs sind alle so vermurkst, die Build Systeme und die
Debugger Unterstützung sind untereinander nicht kompatibel. Den gcc
scheint es aber nicht zu stören wenn man zusätzlich noch -std=c++17
hinzu fügt.
Ich bin immer noch dabei zu lernen, auch wenn es langsamer geht ;-)
Hans-Georg L. schrieb:> Im Moment versuche ich meine C Programme für die STM32 MC auf C++ um zu> stellen und da sind Klassen eher unwichtig und die neuen Features sehr> willkommen.
So sehe ich es auch: OOP auf Mikrocontrollern in Embedded Systemen
braucht man oft nicht, bzw. bringt für viele typische Anwedungsfälle
(z.B. Abarbeiten eines Schnittstellenprotokolls) oft keine nennenswerten
Vorteile gegenüber prozeduraler Programmierung. Aber C++ ist eben nicht
nur OOP. Man sagt ja auch, es sei eine "multi-paradigm"
Programmiersprache.
Hans-Georg L. schrieb:> Im Moment versuche ich meine C Programme für die STM32 MC auf C++ um zu> stellen und da sind Klassen eher unwichtig und die neuen Features sehr> willkommen.
Klassen sind an der Stelle sehr(!) wichtig. Und zwar als die Basis der
Meta-Programmierung. Denn Meta-Funktionen F: type -> type sind im
allgemeinen als Klassentemplates bzw. Spezialisierungen derselben
realisiert.
Was Du allerdings meinst mit Deiner Aussage ist ein Teilbereich der OOP,
nämlich Laufzeitpolymorphie. Das mag für den µC Bereich eher weniger
wichtig sein (in meinen Augen ist es das). Wobei es auch da Ersatz gibt,
der auf µC besser geeignet ist.
Mark B. schrieb:> Man sagt ja auch, es sei eine "multi-paradigm"> Programmiersprache.
Genau: und klassische OOP ist nur ein Teil davon!
Aber selbst von man klassische OOP nicht einsetzt, heißt dass nicht,
dass Klassen (in C++) unnütz sind ...
Wilhelm M. schrieb:> Hans-Georg L. schrieb:>> Im Moment versuche ich meine C Programme für die STM32 MC auf C++ um zu>> stellen und da sind Klassen eher unwichtig und die neuen Features sehr>> willkommen.>> Klassen sind an der Stelle sehr(!) wichtig. Und zwar als die Basis der> Meta-Programmierung. Denn Meta-Funktionen F: type -> type sind im> allgemeinen als Klassentemplates bzw. Spezialisierungen derselben> realisiert.>> Was Du allerdings meinst mit Deiner Aussage ist ein Teilbereich der OOP,> nämlich Laufzeitpolymorphie. Das mag für den µC Bereich eher weniger> wichtig sein (in meinen Augen ist es das). Wobei es auch da Ersatz gibt,> der auf µC besser geeignet ist.
Wenn ich mich undeutlich ausdrücke darfst du mich gerne korrigieren ;-)
Ich lerne gerne dazu ...
Mein Bestreben war es erst einmal das C Konstrukt :
RCC->AHB1ENR = GPIOA | 1<<GPIOB | 1<<GPIOC /*usw...*/ ;
durch eine typsichere und einfach verständliche C++ Version zu ersetzen.
Meine Version:
AHB1_EnableClock(GPIOA_CLK,GPIOB_CLK,GPIOC_CLK);
Meine Datentypen sind enums und die kann man in diesem Zusammenhang auch
als Klassen sehen.
Anbei noch ein Code Ausschnitt dazu.
ps .. die enums lassen sich auch noch nach read/write only erweitern
Hau wech den Scheiss schrieb:> Hans-Georg L. schrieb:>>> Anbei noch ein Code Ausschnitt dazu.>> Zeile 40 enthält einen Fehler.
Danke.
Das ist nur ein erster Versuch im Endeffekt möchte ich diese
Declarationen wenn ich mir über die Strukturierung der namespaces klar
bin, automatisch aus dem svd File erzeugen aber auch diese sind nicht
unbedingt Fehlerfrei.
Hans-Georg L. schrieb:> automatisch aus dem svd File erzeugen aber auch diese sind nicht> unbedingt Fehlerfrei.
Vielleicht einen Plausibilitätscheck drüber laufen lassen, der auf
doppelte vergebenen Addressen schaut.
Misaligment für dword-Adressen wäre auch so ein Check der sich anbietet,
aber letzteres sollte doch auch der Assembler finden und als Warning
bemeckern. Vielleicht auch aus den pdf-docs mit tesseract rauspulen wenn
man den mitgelieferten Headern nicht trauen kann.
Hau wech den Scheiss schrieb:> Hans-Georg L. schrieb:>> automatisch aus dem svd File erzeugen aber auch diese sind nicht>> unbedingt Fehlerfrei.>> Vielleicht einen Plausibilitätscheck drüber laufen lassen, der auf> doppelte vergebenen Addressen schaut.>> Misaligment für dword-Adressen wäre auch so ein Check der sich anbietet,> aber letzteres sollte doch auch der Assembler finden und als Warning> bemeckern. Vielleicht auch aus den pdf-docs mit tesseract rauspulen wenn> man den mitgelieferten Headern nicht trauen kann.
Guter Tip, das könnte ich dann alles in mein Programm einbauen das die
svd Files einliest.
Hans-Georg L. schrieb:> Wenn ich mich undeutlich ausdrücke darfst du mich gerne korrigieren ;-)> Ich lerne gerne dazu ...>> Mein Bestreben war es erst einmal das C Konstrukt :> RCC->AHB1ENR = GPIOA | 1<<GPIOB | 1<<GPIOC /*usw...*/ ;> durch eine typsichere und einfach verständliche C++ Version zu ersetzen.
Wunderbar. Das ist der erste Schritt.
1
template<reg32_tra,typenameT,typename...Args>
2
requires((...&&std::is_same<Args,T>{}))
3
constexprvoidset_bit(Args...args){
4
// static_assert((... && std::is_same<Args, T>())); // parameter test
5
reg32_tmask=(...|args);// folding OR
6
*reinterpret_cast<volatilereg32_t*>(ra)|=mask;// set bitmask
7
};
Ich habe Dein static_assert() mal durch ein adhoc-requirement ersetzt.
DAs macht die Fehlermeldung ggf. intuitiver.
Desweiteren ist es eher unüblich, die traits zu instanziieren und dann
implizit nach bool zu koinvertieren.
1
template<reg32_tra,typenameT,typename...Args>
2
constexprvoidclear_bit(Args...args){
3
static_assert((...&&std::is_same_v<Args,T>));// parameter test
Habe das mal kurz hier geändert, nur als Idee.
Du könntest dann auch noch scoped-enums einsetzen.
Statt extra Funktionen für set/clear einzuführen, kannst Du nach dem
gleichen Muster ggf. die Op-|| und Op-&& für die Typen überladen. Ggf.
sogar als template und per enable-if/concept ganz gezielt aktivieren für
die Typen, für die Du das haben möchtest.
Hans-Georg L. schrieb:>> Misaligment für dword-Adressen wäre auch so ein Check der sich anbietet,>> aber letzteres sollte doch auch der Assembler finden und als Warning>> bemeckern. Vielleicht auch aus den pdf-docs mit tesseract rauspulen wenn>> man den mitgelieferten Headern nicht trauen kann.>> Guter Tip, das könnte ich dann alles in mein Programm einbauen das die> svd Files einliest.
Da könnte aber auch eine IMHO sinnvolle Erweiterung der
Programmiersprache sein, das man Typen nicht nur entsprechend Bitbreite
und Vorzeichen definiert, sondern auch nach dem 'Alignment'. Also Hier
einen Typen für die Registeraddressen vorsehen der nur Konstanten endend
auf 0x0, 0x4, 0x8 oder 0xC zulässt.
Scripte zur Fehlersuche, -vermeidung über den Code einzusetzen scheint
mir aber ein universeller Ansatz, der auch für andere Sprachen
einsetzbar ist. Also generische Prüfscripte für jede
Prozessorarchitektur (auch FPGA eigene Prozessoren) die den C/C++/? Code
auf 'offensichtliche Merkwürdigkeiten' durchsucht.
Die 'merkwürdigen Stellen' hatte ich schon in einer Minute drüberfliegen
gefunden, das Raussuchen von Datenblatt und Vergleich hat dann ein
Mehrfaches an Zeit gekostet.
Hau wech den Scheiss schrieb:> Da könnte aber auch eine IMHO sinnvolle Erweiterung der> Programmiersprache sein, das man Typen nicht nur entsprechend Bitbreite> und Vorzeichen definiert, sondern auch nach dem 'Alignment'.
Das haben C und C++ schon lange. Kann man seit C++11 (na sowas) auch
explizit festlegen mit dem "alignas" Keyword. Allerdings ist der
manuelle Zugriff auf beliebige Speicherstellen durch Umcasten von
Adressen sowieso nicht vorgesehen und ein Missbrauch der Sprache,
weshalb da auch die Adresse nicht geprüft wird.
Hau wech den Scheiss schrieb:> Scripte zur Fehlersuche, -vermeidung über den Code einzusetzen scheint> mir aber ein universeller Ansatz, der auch für andere Sprachen> einsetzbar ist.
Diese sind allerdings schwierig in komplexe Sprachen zu integrieren,
weil man hier alle Sprachkonstrukte korrekt verarbeiten muss.
Glücklicherweise kann man in C++ dank Metaprogrammierung und statischer
Typisierung eine Menge Prüfungen direkt in der Sprache vornehmen, die
dann bei jedem kompilier-Vorgang direkt vom Compiler geprüft werden,
ganz ohne externe Skripte. Hier z.B. mit:
1
static_assert((ra%4)==0,"Address not aligned");
Hier zeigt sich der Nachteil der klassischen C-Programmierung: Diverse
Funktionalität muss man durch externe Tools nachbilden (Fehlersuche,
Code-Generierung), während man in mächtigeren Sprachen wie C++ diese
Dinge einfach direkt schon integriert hat.
Was mich immer wieder nervt ist, dass es praktisch unmöglich ist
einfache Ausdrücke wie:
GPIOA->BSS = 1<<5;
So z.b. in Templates zu verpacken dass am Ende ein asm Zweizeiler dabei
rauskommt auch wenn die Optimierung des Kompilers zum Debuggen
ausgeschaltet ist. Mit eingeschalteter Optimierung ist das kein Problem.
Oder anders gefragt, wie baut man z.B. eine Gpio Klasse so, dass sie
nicht während des Debuggens 5 mal langsamer wird? Leider ist es bis
heute so, will man beim Debuggen und im Release annähernd gleiche
Resultate beim erzeugten Code, geht um ein C—Macro auch 2021 immer noch
kein Weg vorbei. Ich lasse mich aber gern eines besseren Belehren.
temp schrieb:> Leider ist es bis> heute so, will man beim Debuggen und im Release annähernd gleiche> Resultate beim erzeugten Code, geht um ein C—Macro auch 2021 immer noch> kein Weg vorbei. Ich lasse mich aber gern eines besseren Belehren.
Du kannst doch sicher -Og benutzen. Das reicht aus, um die
template-calls (inline) zu optimieren.
Die obige Lösung kannst Du natürlich verbessern, und möglichst viel zur
Compilezeit erledigen:
1
template<reg32_tadr,auto...Args>
2
constexprvoidenable(){
3
constexprreg32_tmask=(...|Args);
4
*reinterpret_cast<volatilereg32_t*>(adr)|=mask;
5
}
(Oder Du schreibst noch eine Meta-Funktion für den |-Op, ist wegen
constexpr aber unnötig, etwa static_or<...>).
Mit dem static_or dann:
Wilhelm M. schrieb:> temp schrieb:>> Leider ist es bis>> heute so, will man beim Debuggen und im Release annähernd gleiche>> Resultate beim erzeugten Code, geht um ein C—Macro auch 2021 immer noch>> kein Weg vorbei. Ich lasse mich aber gern eines besseren Belehren.>> Du kannst doch sicher -Og benutzen. Das reicht aus, um die> template-calls (inline) zu optimieren.>> Die obige Lösung kannst Du natürlich verbessern, und möglichst viel zur> Compilezeit erledigen:>> [c]> template<reg32_t adr, auto ... Args>> constexpr void enable() {> constexpr reg32_t mask = (... | Args);> *reinterpret_cast<volatile reg32_t*>(adr) |= mask;> }Wilhelm M. schrieb:> template<reg32_t ra,typename T, typename ... Args>> requires((... && std::is_same<Args, T>{}))> constexpr void set_bit(Args ... args ) {> // static_assert((... && std::is_same<Args, T>())); //> parameter test> reg32_t mask =(... | args); // folding OR> *reinterpret_cast<volatile reg32_t*>(ra) |= mask; // set bitmask> };>> Ich habe Dein static_assert() mal durch ein adhoc-requirement ersetzt.> DAs macht die Fehlermeldung ggf. intuitiver.>
requires ist c++20 und wie schon geschrieben ist mein compiler auf c++17
begrenzt aber eine sinnvolle Fehlermeldung könnte ich noch ausgeben
> Desweiteren ist es eher unüblich, die traits zu instanziieren und dann> implizit nach bool zu koinvertieren.> template<reg32_t ra,typename T, typename ... Args>> constexpr void clear_bit(Args ... args ) {> static_assert((... && std::is_same_v<Args, T>)); // parameter> test> reg32_t mask =(... | args); // folding OR> *reinterpret_cast<volatile reg32_t*>(ra) &= ~mask; // clear> bitmask> };>
Finde den Unterschied nicht so leicht für ältere Augen ;-)
> Du könntest dann auch noch scoped-enums einsetzen.
Das wollte ich sowieso und vorsichtshalber den underlying typ auf
unsigned ändern. Nicht das der Compiler, durch Bit-Schiebereien,
irgendwann auf die Idee kommt Bit31 als Vorzeichen aufzufassen.
> Statt extra Funktionen für set/clear einzuführen, kannst Du nach dem> gleichen Muster ggf. die Op-|| und Op-&& für die Typen überladen. Ggf.> sogar als template und per enable-if/concept ganz gezielt aktivieren für> die Typen, für die Du das haben möchtest.
Ich bin ehrlich gesagt kein großer Freund davon erstmal alles zusammen
zu fassen und dann wieder mit if zu zerlegen. Mal sehen.. es gibt ja
noch andere Registertypen.
Hans-Georg L. schrieb:> Ich bin ehrlich gesagt kein großer Freund davon erstmal alles zusammen> zu fassen und dann wieder mit if zu zerlegen
Nicht if, sondern enable-if.
Mit -Og hab ich auch schon gespielt. Kennen aber auch nicht alle
Compiler. Das kann aber auch nicht die Lösung sein. Mit #pragma kann man
auch für bestimmte Teile im Code eine gezielt anderen Optimierung
verwenden. Allerdings brachte das bisher keinen Erfolg. Ich mache jetzt
schon nur bei den Dateien die ich Debugge den Schalter auch an, sonst
passt ein Release Code von 20k schon nicht mehr in 32k Flash. Trotzdem
nervt mich das einfach nur und hindert mich auch daran Lobeshymnen auf
C++ im embedded Bereich zu singen. Was nützt das alles, wenn man zwar
schöne Programme schreiben kann, die am Ende aber nicht vernünftig
debugbar sind oder beim Debuggen 3 mal so groß. Bei der PC
Programmierung stört mich das nicht.
Hans-Georg L. schrieb:> requires ist c++20 und wie schon geschrieben ist mein compiler auf c++17> begrenzt
Ist das ein gcc? Und c++2a kann der noch nicht?
Das requires dannst Du ggf. auch durch ein enable-if ersetzen, um die
Instantiierung aus dem overload-set zu entfernen.
Wilhelm M. schrieb:> Hans-Georg L. schrieb:>> requires ist c++20 und wie schon geschrieben ist mein compiler auf c++17>> begrenzt>> Ist das ein gcc? Und c++2a kann der noch nicht?>> Das requires dannst Du ggf. auch durch ein enable-if ersetzen, um die> Instantiierung aus dem overload-set zu entfernen.
Es ist wie geschrieben ein gcc 9.3.1 der sich mit STM CUBE-IDE (Eclipse)
maximal auf c++14 stellen lässt. Aber man kann zusätzlich c++17
einfügen, was er dann auch benutzt. Das funktioniert auch mit
-std=c++2a. :-)
gibt es auch eine Option zum Removen einer anderen Option ? Also um das
-std=c++14 los zu werden.
Hans-Georg L. schrieb:> Es ist wie geschrieben ein gcc 9.3.1
Sorry, hatte ich nicht gelesen.
Im übrigen ist das Compilieren des Gcc aus dem git-repo kein Problem.
temp schrieb:> Was nützt das alles, wenn man zwar> schöne Programme schreiben kann, die am Ende aber nicht vernünftig> debugbar sind oder beim Debuggen 3 mal so groß.
Du könntest zur Entwicklung/Debugging einen größeren Controller mit mehr
Flash nehmen und dann für die Serienproduktion wo es auf's Geld ankommt
den kleinstmöglichen. Mit __attribute__((always_inline)) kann man sich
auch schon gut behelfen, oder indem man nur einzelne Dateien ohne
Optimierung kompiliert. IMO ist es aber auch gar nicht so schlimm
optimierten Code zu debuggen. Der Cursor springt halt ein bisschen
lustig herum.
Hans-Georg L. schrieb:> gibt es auch eine Option zum Removen einer anderen Option ? Also um das> -std=c++14 los zu werden.
Das ist ein Problem des Cube-Eclipse-Plugins, nicht des Compilers. Da
musst du dich an die dazu zuständigen Programmierer wenden.
Andere Plugins bieten in dem Auswahlfeld zumindest ein leeres Feld an.
Oliver
Oliver S. schrieb:> Hans-Georg L. schrieb:>> gibt es auch eine Option zum Removen einer anderen Option ? Also um das>> -std=c++14 los zu werden.>> Das ist ein Problem des Cube-Eclipse-Plugins, nicht des Compilers. Da> musst du dich an die dazu zuständigen Programmierer wenden.>> Andere Plugins bieten in dem Auswahlfeld zumindest ein leeres Feld an.>> Oliver
Unter Window->Preferences->StmCube->Build gibt es dieses Leerfeld.
Unter den Project->settings aber dann nicht mehr.
Dieses Plugin hat mich schon Nerven gekostet. Ich benutze die Cube IDE
nur weil man damit problemlos zwischen ST-Link und Segger J-Link
umschalten kann und der Build mit dem CubeMX Code kompatibel ist was
bei anderen, wo man seinen eigenen Compiler einbinden kann leider nicht
funktioniert. Und anpassen kann man bei allen selbst nichts, sondern
muss irgendwo betteln das es einer macht.
Hans-Georg L. schrieb:> Ich benutze die Cube IDE> nur weil man damit problemlos zwischen ST-Link und Segger J-Link> umschalten kann
Das geht mit dem GNU-MCU-Eclipse Plugin auch.
Hans-Georg L. schrieb:> und der Build mit dem CubeMX Code kompatibel ist was> bei anderen, wo man seinen eigenen Compiler einbinden kann leider nicht> funktioniert.
Wieso das? Die CubeIDE nutzt auch nur den normalen GCC-ARM-Embedded.
Wenn man den separat herunterlädt (und ggf. in eine beliebige IDE
einbindet) kann man damit auch den CubeMX-generierten Code kompilieren.
Wenn das bei dir nicht klappt hast du irgendwas falsch gemacht (Makros
vergessen oder so).
Programmierer schrieb:> Hans-Georg L. schrieb:>> Ich benutze die Cube IDE>> nur weil man damit problemlos zwischen ST-Link und Segger J-Link>> umschalten kann>> Das geht mit dem GNU-MCU-Eclipse Plugin auch.>> Hans-Georg L. schrieb:>> und der Build mit dem CubeMX Code kompatibel ist was>> bei anderen, wo man seinen eigenen Compiler einbinden kann leider nicht>> funktioniert.>> Wieso das? Die CubeIDE nutzt auch nur den normalen GCC-ARM-Embedded.> Wenn man den separat herunterlädt (und ggf. in eine beliebige IDE> einbindet) kann man damit auch den CubeMX-generierten Code kompilieren.> Wenn das bei dir nicht klappt hast du irgendwas falsch gemacht (Makros> vergessen oder so).
Es geht nicht um den Code sondern die .(c)project files. Irgendwann hast
du eine Sammlung von .project files die untereinander nicht kompatibel
sind.
Diese Baustelle möchte ich nicht mehr öffnen ;-)
Hans-Georg L. schrieb:> Es geht nicht um den Code sondern die .(c)project files. Irgendwann hast> du eine Sammlung von .project files die untereinander nicht kompatibel> sind.
Achso. Die sind aber bei Verwendung des GNU-MCU-Plugin flugs angelegt.
Sich deswegen auf die STM32CubeIDE festzulegen ist Jammern auf hohem
Niveau.
Programmierer schrieb:> IMO ist es aber auch gar nicht so schlimm> optimierten Code zu debuggen. Der Cursor springt halt ein bisschen> lustig herum.
Ne, das ist absoluter Mist. Dann nehme ich lieber printf und überhaupt
keinen Debugger.
Was nützt es mir einen Breakpoint zu setzen, der sich nicht an die
Regeln im Code hält weil er halt durch die Optimierung entweder garnicht
mehr da ist oder nichts mehr mit dem Quellcode zu tun hat. Sollten die
Werkzeugen nicht dazu da sein mir die Arbeit zu erleichtern? Aber nein
jetzt muss man sich wieder Gedanken darum machen wie und wann der
Compiler optimiert? Schöne neue constexpr Welt. Das kann der
Präprozessor seit 50 Jahren aber besser...
Und das ganze Geschwafel von Typesicherheit ist überflüssig wie ein
Kropf. Jedenfalls im embedded Bereich. Wenn jemand solche Klötze wie
boost anbietet, mag das seine Berechtigung haben. Das paradoxe an C++
ist hat, mit jeder Erweiterung (c++11/14/17) wurde die Tipparbeit immer
mehr. Endlos lange Zeilen die mehr verwirren als nützen. Jetzt macht man
gerade wieder die Rolle Rückwärts und macht neue Erweiterungen damit es
wieder kürzer wird. Aber schön, es wollen ja schließlich Leute dafür
bezahlt werden sich immer wieder neue Formen für den Kopf einer for(;;)
einfallen zu lassen. Am Ende entscheidet sich jeder Entwickler für seine
persönliche Vorliebe, kriegt er dann mal fremden Code vorgeschmissen ist
das dann erst mal wie eine neue Sprache. Ich bin beeindruckt.
Jaja, früher war alles besser. Hab gar keine Lust den ganzen Blödsinn zu
widerlegen. Nur für andere Mitleser: Ein strategisch platziertes
'__BKPT();' bzw. '__asm__ volatile ("bkpt" : : : "memory");' kann im
Notfall, wenn normale Breakpoints gar nicht funktionieren wollen,
helfen.
temp schrieb:> Das paradoxe an C++> ist hat, mit jeder Erweiterung (c++11/14/17) wurde die Tipparbeit immer> mehr.
Das stimmt nicht, zumindest nicht in dieser Pauschalität. 7 der 9 von
mir oben genannte Vorzüge von C++≥11
Yalu X. schrieb:> Die für mich wichtigsten positiven Punkte sind:
führen zu kompakterem und übersichtlicherem Code. Die verbleibenden 2
(Punkte 6 und 7) erfordern zwar etwas mehr Tipparbeit, helfen aber bei
der Aufdeckung von Programmierfehlern, deren Suche sonst i.Allg. mehr
Zeit beansprucht als die paar zusätzlich zu tippenden Zeichen.
Programmierer schrieb:> Jaja, früher war alles besser. Hab gar keine Lust den ganzen Blödsinn zu> widerlegen. Nur für andere Mitleser: Ein strategisch platziertes> '__BKPT();' bzw. '__asm__ volatile ("bkpt" : : : "memory");' kann im> Notfall, wenn normale Breakpoints gar nicht funktionieren wollen,> helfen.
Das hat nichts mit früher war alles besser zu tun. Solange das "heute
ist alles viel besser" solche Klimmzüge erfordert die vorher nicht nötig
waren ist das Neue eben nicht besser. Und wenn das ganze schon bei der
Implementierung einer einfachen Gpio-Klasse dazu führt, dass ich
schlechter Debuggen kann, ist und bleibt es Mist. Wie gesagt, vielleicht
bin ich ja zu blöd und ihr wisst es alle besser. Dann aber bitte ein
Beispiel liefern wie man dem Compiler beibringen kann seine Berechnungen
zur Compilierzeit zu machen ohne in der Datei wo es verwendet wird
expliziet einen Optimierungslevel angeben zu muessen. Das hab ich mal
kurz mit dem Simulator vom Segger Embedded Studio probiert. Bitte nur
überprüfte Vorschläge machen.
Wilhelm M. schrieb:> Mit dem static_or dann:> *reinterpret_cast<volatile reg32_t*>(Regs::RCC_AHB1ENR) => static_or_v<CRC_CLK,GPIOA_CLK,GPIOB_CLK,GPIOC_CLK,GPIOD_CLK>;>> bzw:> GPIOA->BSS = static_or_v<...>;>> Auf die Typ-Prüfungen habe ich jetzt verzichtet, kann man aber ja noch> obigem Muster ebenfalls einbauen.
Jetzt muss mir einmal jemand verraten welchen Vorteil es bring so eine
Konstruktion als Ersatz von
zu verwenden. Und sowas wie "Regs::RCC_AHB1ENR" setzt voraus, dass alle
Registerdefinitionen der CPU neu geschrieben werden müssen. Einen
Vorteil hat das dann, man lernt seinen Controller gut kennen...
ohne Optimierungslevel werden auch wieder richtige Funktionscalls
erzeugt.
das "gute Alte" würde so aussehen:
1
while(1)
2
{
3
GPIOA->BSRR=GPIO_BSRR_BS_5;
4
GPIOA->BSRR=GPIO_BSRR_BR_5;
5
}
und erzeugt unabhängig von der Optimierung den gleichen kurzen
Assemblercode. Quintessenz: Man erkauft sich mit den Vorteilen des
"guten Neuen" neue Hürden die beim "verschmäten Alten" garnicht erst
auftreten.
Wilhelm M. schrieb:> Gerade Ast schrieb:>> Was mir nicht so gut gefällt, ist daß die "uniform initialisation" nicht>> der alten Initialisierung gleichwertig ist:>> Und das ist m.E. gut so!
Das kann man so sehen oder auch nicht. "Gerade Ast", meine Wenigkeit und
viele andere sehen das offensichtlich anders als du.
Wie ich oben schon schrieb und das Beispiel von "Gerade Ast" deutlich
zeigt, ist die "uniform initialization" alles andere als "uniform".
Rätselfrage: Was gibt folgendes Programm aus?
Oliver S. schrieb:> Das kommt u.a, darauf an, ob MyClassX ein int ist...
Richtig, oder ob MyClassX einen Konstruktor mit int-Argument hat oder
ob int in MyClassX konvertierbar ist ...
Kurz: Verwendet man die uniform Initialization (v1 und v2), muss man
sich in myclasses.h die Typ- bzw. Klassendefinition von MyClassX
anschauen. Mit der klassischen Initialisierung (v3 und v4) ist das
Verhalten sofort ohne weitere Nachforschungen erkennbar.
Wilhelm M. schrieb:> std::vector<MyClass1> v1(2, 3);
Was ist daran Besonderes? Bei zwei int-Argumenten ist das erste die
Anzahl der Elemente, und damit ist v1.size() auch ohne Kenntnis der
Klassendefinition eindeutig bestimmt, oder nicht?
Yalu X. schrieb:> Wilhelm M. schrieb:>> std::vector<MyClass1> v1(2, 3);>> Was ist daran Besonderes?
Ich finde die "uniform initialization" konsistenter:
1
{
2
std::vector<int>v1();// ups
3
std::vector<int>v2(3);
4
std::vector<int>v3(3,2);// ist das [2, 2, 2] oder [3, 3] ?
5
std::vector<int>v4(2,3);
6
// std::vector<int> v5(1, 2, 3); // warum geht das nicht?
// std::array<int, 10> a2(3); // warum geht das nicht?
18
}
19
{
20
std::array<int,10>a1{};
21
std::array<int,10>a2{3};
22
std::array<int,10>a3{3,2};
23
std::array<int,10>a4{1,2,3};
24
}
25
{
26
inti0;// ?
27
inti1();// ups
28
inti2(4);// s.o. Konsistenz
29
}
30
{
31
inti0{};// num. Standardwert
32
inti1{};
33
inti2{4};
34
}
Yalu X. schrieb:> Kurz: Verwendet man die uniform Initialization (v1 und v2), muss man> sich in myclasses.h die Typ- bzw. Klassendefinition von MyClassX> anschauen. Mit der klassischen Initialisierung (v3 und v4) ist das> Verhalten sofort ohne weitere Nachforschungen erkennbar.
Was Du hier zitierst, ist nicht ein Thema der uniform-initialization,
sondern es ist Design-Defekt von std::vector<>. Dieser entsteht durch
Abwärtskompatibilität, was m.E. auch ein sehr hohes Gut ist.
Der ctor std::vector<T>(int) bzw. std::vector<T>(int, T) gehören nicht
in die Schnittstelle (zumindest wenn T=int; das sieht man auch daran,
dass dann die Bedeutung der beiden int nicht klar ist -> Strong-Types).
Da die jedoch vorher da waren, war es ein Fehler, den
std::vector<T>(std::initializer_list<T>) hinzuzunehmen (Dies ist ja auch
schon oft diskutiert worden, aber wegen Abwärtskompatibiliät ... nun
ja).
Eine Variante wäre es gewesen, in einem anderen Namensraum ein korrekte
Variante von vector<> anzubieten.
Wilhelm M. schrieb:> Was Du hier zitierst, ist nicht ein Thema der uniform-initialization,> sondern es ist Design-Defekt von std::vector<>.
Ob man den Design-Defekt dem std::vector oder der uniform Initialization
zuschreibt, ist IMHO Ansichtssache. Fest steht, dass dieser "Defekt" vor
der Einführung der uniform Initialization nicht in Erscheinung trat.
> Der ctor std::vector<T>(int) bzw. std::vector<T>(int, T) gehören nicht> in die Schnittstelle (zumindest wenn T=int;
Ich finde den Konstruktor zur Initialisierung des Vektors mit n gleichen
Elementen ganz praktisch.
> das sieht man auch daran, dass dann die Bedeutung der beiden int nicht> klar ist -> Strong-Types).
Dann wäre also jede Funktion mit zwei oder mehr Argumenten gleichen Typs
defekt? Dann müssten deiner Ansicht nach auch die pow- und die
atan2-Funktion und sogar die Operatoren für Subtraktion und Division
abgeschafft werden? Alternativ könnte man spezielle Datentypen für
Basis, Exponent, y-Koordinate, x-Koordinate, Minuend, Subtrahend,
Dividend und Divisor einführen. Ich bin mir aber sicher: Wenn dies
geschehen würde, würde C++ 90% seiner Gefolgschaft verlieren.
> Da die jedoch vorher da waren, war es ein Fehler, den> std::vector<T>(std::initializer_list<T>) hinzuzunehmen
Diese ist aber eine der wirklich wertvollen Neuerungen von C++, auf die
ich nicht verzichten wollte. Sie beißt sich auch überhaupt nicht mit
bestehenden Features der Sprache. Der Konflikt entsteht erst im
Zusammenhang mit der – IMHO weitgehend nutzlosen – uniform
Initialization. Letztere wurde nicht vor sondern zusammen mit der
initializer_list (beides C++11) eingeführt, deswegen lag hier der große
Fehler. Diesen Fehler umschiffe ich, indem ich die uniform
Initialization einfach nicht nutze. Es wäre schön, wenn jeder, mit
dessen Quellcode ich arbeiten muss, ebenso handeln würde.
Wilhelm M. schrieb:> Eine Variante wäre es gewesen, in einem anderen Namensraum ein korrekte> Variante von vector<> anzubieten.
Eine sehr viel einfachere und elegantere Variante wäre es gewesen, die
uniform Initialization komplett wegzulassen. Für mich scheint das ein
Feature zu sein, dass einfach nicht zu Ende gedacht wurde.
Wilhelm M. schrieb:> Ich finde die "uniform initialization" konsistenter:> {> std::vector<int> v1(); // ups> std::vector<int> v2(3);> std::vector<int> v3(3, 2); // ist das [2, 2, 2] oder [3, 3] ?> std::vector<int> v4(2, 3);> // std::vector<int> v5(1, 2, 3); // warum geht das nicht?
Ist doch einfach. Der erste Parameter ist hier immer die Größe. Das ist
auch ganz unabhängig vom Elementtyp des vectors.
> }> {> std::vector<int> v1{};> std::vector<int> v2{3};> std::vector<int> v3{3, 2};> std::vector<int> v4{2, 3};> std::vector<int> v5{1, 2, 3};> }
Wie mache ich einen vector, der 100 default-initialisierte Elemente hat?
Wilhelm M. schrieb:> Was Du hier zitierst, ist nicht ein Thema der uniform-initialization,> sondern es ist Design-Defekt von std::vector<>. Dieser entsteht durch> Abwärtskompatibilität, was m.E. auch ein sehr hohes Gut ist.
Das ist eben die Crux. Ja, Abwärtskompatibilität ist wichtig, und ja,
viele der neuen Features haben durchaus ihre Berechtigung, aber es macht
die Sprache auch sehr unübersichtlich.
Yalu X. schrieb:> Wilhelm M. schrieb:>> Was Du hier zitierst, ist nicht ein Thema der uniform-initialization,>> sondern es ist Design-Defekt von std::vector<>.>> Ob man den Design-Defekt dem std::vector oder der uniform Initialization> zuschreibt, ist IMHO Ansichtssache.
Ja. Offensichtlich sind wir da schon lange unterschiedlicher Ansicht.
Wir hatten in anderen Threads schon desöfteren darüber geredet.
> Fest steht, dass dieser "Defekt" vor> der Einführung der uniform Initialization nicht in Erscheinung trat.
Ja. Für den Grund: s.o.
Dafür gab es andere: most-vexing-parse, keine list-initialisierung, ...
>> Der ctor std::vector<T>(int) bzw. std::vector<T>(int, T) gehören nicht>> in die Schnittstelle (zumindest wenn T=int;>> Ich finde den Konstruktor zur Initialisierung des Vektors mit n gleichen> Elementen ganz praktisch.
Ich auch ;-) Das kann ja auch so bleiben. Falls Du das anders verstanden
hast, dann hast Du mich oben falsch verstanden. Es ging um den
mehrstelligen ctor.
>> das sieht man auch daran, dass dann die Bedeutung der beiden int nicht>> klar ist -> Strong-Types).>> Dann wäre also jede Funktion mit zwei oder mehr Argumenten gleichen Typs> defekt?
Grundsätzlich: ja. Mehrstellige Funktionen mit denselben, unspezifischen
Datentypen sind m.E. zu vermeiden.
> Dann müssten deiner Ansicht nach auch die pow- und die> atan2-Funktion und sogar die Operatoren für Subtraktion und Division> abgeschafft werden?
Nein. Du musst nicht gleich das Kinde mit dem Bade ausschütten.
>> Da die jedoch vorher da waren, war es ein Fehler, den>> std::vector<T>(std::initializer_list<T>) hinzuzunehmen>> Diese ist aber eine der wirklich wertvollen Neuerungen von C++, auf die> ich nicht verzichten wollte. Sie beißt sich auch überhaupt nicht mit> bestehenden Features der Sprache.
Genau.
> Der Konflikt entsteht erst im> Zusammenhang mit der – IMHO weitgehend nutzlosen – uniform> Initialization.
Und da bin ich eben anderer Meinung: s.o.. Die beiden ctoren (s.o.)
hätte man eben abschaffen müssen, was natürlich nicht geht. Da die Sache
aber seit Urzeiten verbockt ist, hätte man es anders lösen müssen.
> Diesen Fehler umschiffe ich, indem ich die uniform> Initialization einfach nicht nutze. Es wäre schön, wenn jeder, mit> dessen Quellcode ich arbeiten muss, ebenso handeln würde.
Ich mache es anders herum wie Du weißt: ich / wir arbeiten nur mit
uniform-initialisation.
> Wilhelm M. schrieb:>> Eine Variante wäre es gewesen, in einem anderen Namensraum ein korrekte>> Variante von vector<> anzubieten.>> Eine sehr viel einfachere und elegantere Variante wäre es gewesen, die> uniform Initialization komplett wegzulassen. Für mich scheint das ein> Feature zu sein, dass einfach nicht zu Ende gedacht wurde.
Der Fehler ist m.E. gewesen, dass man eben die Konsequenzen speziell im
std::vector<> u.a. nicht bedacht hat. Das kann passieren. Da das Problem
aber schon sehr früh entdeckt und bemängelt wurde. hätte man es auf
verschiedene Weise korrigieren können. Das war der fatale Folgefehler.
Bei den Concepts etwa hat man ja wegen ähnlicher Probleme aus dem TS die
function-style-concepts wieder entfernt - und zwar kurz vor knapp!
Rolf M. schrieb:> Wilhelm M. schrieb:>> Ich finde die "uniform initialization" konsistenter:>> {>> std::vector<int> v1(); // ups>> std::vector<int> v2(3);>> std::vector<int> v3(3, 2); // ist das [2, 2, 2] oder [3, 3] ?>> std::vector<int> v4(2, 3);>> // std::vector<int> v5(1, 2, 3); // warum geht das nicht?>> Ist doch einfach. Der erste Parameter ist hier immer die Größe. Das ist> auch ganz unabhängig vom Elementtyp des vectors.>>> }>> {>> std::vector<int> v1{};>> std::vector<int> v2{3};>> std::vector<int> v3{3, 2};>> std::vector<int> v4{2, 3};>> std::vector<int> v5{1, 2, 3};>> }>> Wie mache ich einen vector, der 100 default-initialisierte Elemente hat?
Vorschlag:
> Wilhelm M. schrieb:>> Was Du hier zitierst, ist nicht ein Thema der uniform-initialization,>> sondern es ist Design-Defekt von std::vector<>. Dieser entsteht durch>> Abwärtskompatibilität, was m.E. auch ein sehr hohes Gut ist.>> Das ist eben die Crux. Ja, Abwärtskompatibilität ist wichtig, und ja,> viele der neuen Features haben durchaus ihre Berechtigung, aber es macht> die Sprache auch sehr unübersichtlich.
s.o. meine "Wunschliste" ;-)
Tom K. schrieb:> Also ich bleibe bei C, im embedded Bereich.
Da spricht auch nichts dagegen. Allerdings war das hier nicht das Thema.
Ich nutze C++, allerdings nicht um jeden Preis. Gerade wenn so ein
kleiner Controller nur 20k RAM hat dürfte die excessive Verwendung der
STL sowieso ausgeschlossen sein. Eigentlich alles was mit dynamischen
Speicher arbeitet. Und wenn man sich schon darauf einlässt, sollte man
auch genau wissen wie die STL intern arbeit um die Grenze ausloten zu
können.
Nach oben gibt es sicher Controller die über genug Resource verfügen.
Wenn es in diese Größenordnung geht nehme ich aber lieber gleich einen
Raspi o.ä. mit ordentlichem Betriebssystem. Da kann man dann auch im C++
Baukasten in die Vollen greifen.
Ups, eben sehe ich dass der ganze Thread unter PC-Programmierung
eingeordnet ist. Da stellt sich die gesamte Frage nicht. Auch die
Debugproblematik bzw. gezielte Optimierung ist da kein Thema. Auf einem
kleinen Controller aber schon.
temp schrieb:> Ich nutze C++, allerdings nicht um jeden Preis. Gerade wenn so ein> kleiner Controller nur 20k RAM hat dürfte die excessive Verwendung der> STL sowieso ausgeschlossen sein.
Gerade für kleine µC nutze nur noch C++, natürlich dann ohne stdlib.
Dadurch werden viel mehr Fehler schon zur Compilezeit aufgedeckt bzw.
verhindert.
temp schrieb:> template<eGpioPort ePort, uint32_t bitPosi>> class GpioPin {}
leider ist das kacke, weil dann alle Interfaces die GpioPin entgegen
nehmen auch templates sein müssen.
Das erzeugt bei GCC mit Optimierung (inkl. LTO) optimalen Code, wenn
das Pin Objekt als const angelegt wird. Dies klappt auch, wenn das
Objekt in andere Objekte via Konstruktor injiziert wird.
Dummerweise failed der GCC, sobald die Klasse einen Konstruktor hat.
Deshalb mache ich bei Gpio eine Ausnahme und benutze kein übergeordnetes
Interface.
interessant schrieb:> leider ist das kacke, weil dann alle Interfaces die GpioPin entgegen> nehmen auch templates sein müssen.
Der sog. CodeBloat, den viele befürchten, ist in der Praxis (bei realen
Programmen und nicht nur Mini-Beispielen) viel geringen - wenn überhaupt
vorhanden, und nicht das Gegenteil eintritt - als man denkt. Verzichtet
man komplett auf dyn. Polymorphie und bei der Modellierung von HW auf
die Erzeugung von Instanzen, macht stattdessen nur stat. Polymorphie und
header-only hat man m.E. nur Vorteile.
interessant schrieb:> temp schrieb:>> template<eGpioPort ePort, uint32_t bitPosi>>> class GpioPin {}>> leider ist das kacke, weil dann alle Interfaces die GpioPin entgegen> nehmen auch templates sein müssen.
Das war hier nicht die Frage, das Beispiel sollte kurz bleiben.
Es ging in dem Beispiel darum, dass es Kacke ist, dass es keinen (mir
bekannten Weg) gibt, solchen einfachen Templates (Einzeiler) mitzuteile,
dass sie bitte auch beim Debuggen inline in ein paar wenige Assembler
Statements übersetzt werden. Also genau das machen was mit einem C-Macro
schon immer ging. Leider konnte mir noch keiner das Gegenteil beweisen.
interessant schrieb:> Das erzeugt bei GCC mit Optimierung (inkl. LTO) optimalen Code, wenn> das Pin Objekt als const angelegt wird.
Das ist jetzt aber nicht dein Ernst? Und dann HAL_xx Aufrufe? Noch
schlimmer gehts nicht.
Ich greife dein Beispiel aber mal auf:
Auch hier gibt es keinen Weg bei ausgeschalteter Optimierung das gleiche
Ergebnis wie mit dem Macro zu erzeugen.
Das Problem ist ja, vieles wird heute in C++ in die Header verlagert.
Viel Funktionalität von der man davon ausgeht es ist getesteter Code.
Die Innereien davon will man meistens nicht debuggen sondern nur seinen
eigenen Code der das benutzt. Und genau dafür um das zu steuern gibt es
irgendwie keine Lösung. Es ist ja genauso als wenn ich zum Debuggen
unter Windows bzw. Linux immer mit den Debug-Versionen alles Systemlibs
arbeiten würde. Auch auf dem PC komme ich immer ins Fluchen, da die
Einzelschrittabarbeitung von Code im Debugger fast unmöglich ist.
Ständig landet man da in den Untiefen der STL, die man ja eigentlich
überhaupt nicht debuggen will. In dieser Hinsicht hat das jetzte
Jahrzehnt jedenfalls keinen Fortschritt gebracht.
Wilhelm M. schrieb:> interessant schrieb:>> leider ist das kacke, weil dann alle Interfaces die GpioPin entgegen>> nehmen auch templates sein müssen.>> Der sog. CodeBloat, den viele befürchten, ist in der Praxis (bei realen> Programmen und nicht nur Mini-Beispielen) viel geringen - wenn überhaupt> vorhanden, und nicht das Gegenteil eintritt - als man denkt. Verzichtet> man komplett auf dyn. Polymorphie und bei der Modellierung von HW auf> die Erzeugung von Instanzen, macht stattdessen nur stat. Polymorphie und> header-only hat man m.E. nur Vorteile.
Da bin ich der gleichen Meinung und Bloat kann man auch mit C erzeugen.
z.B. die STM-HAL erzeugt nicht so knapp Bloat im RAM.
temp schrieb:
snip ...
> Auch hier gibt es keinen Weg bei ausgeschalteter Optimierung das gleiche> Ergebnis wie mit dem Macro zu erzeugen.> Das Problem ist ja, vieles wird heute in C++ in die Header verlagert.> Viel Funktionalität von der man davon ausgeht es ist getesteter Code.> Die Innereien davon will man meistens nicht debuggen sondern nur seinen> eigenen Code der das benutzt. Und genau dafür um das zu steuern gibt es> irgendwie keine Lösung. Es ist ja genauso als wenn ich zum Debuggen> unter Windows bzw. Linux immer mit den Debug-Versionen alles Systemlibs> arbeiten würde. Auch auf dem PC komme ich immer ins Fluchen, da die> Einzelschrittabarbeitung von Code im Debugger fast unmöglich ist.> Ständig landet man da in den Untiefen der STL, die man ja eigentlich> überhaupt nicht debuggen will. In dieser Hinsicht hat das jetzte> Jahrzehnt jedenfalls keinen Fortschritt gebracht.
Ich habe das gerade mit meinem geposteten Code und mit dem gcc 9.3.1
-std=c++17 -Og gestestet. Beim debugger single step landet er direct in
meinem "set_bit" mit der Einschränkung das ich mir nicht den parameter
pack angucken kann. Damit kann ich aber leben. Kommt halt darauf an was
man will. Ich will z.b. meine selbst geschriebene lib debuggen , aber
die std libs nicht.
@Wilhelm M
requires kennt der gcc erst ab version 10.
ps. ich habe den Code nochmal angehängt damit man nicht lange suchen
muss.
Hans-Georg L. schrieb:> Damit kann ich aber leben. Kommt halt darauf an was> man will. Ich will z.b. meine selbst geschriebene lib debuggen , aber> die std libs nicht.
Die selbst geschriebenen Libs debuggt man aber nur solange man sie
schreibt. Irgendwann wirst du die ja auch mal benutzen.
Deinen Code oben würde ich nicht mal ansatzweise in Erwägung ziehen.
Alles was nicht mit den Definitionen aus den Headern des Controllers
auskommt, kommt für mich nicht in Frage. Ebensowenig wie irgendwelche
HAL Libs wie bei STM. Aber das sind perönliche Vorlieben.
Al Fine schrieb:> Also da musst du den Debugger richtig konfigurieren.
Danke, das kannte ich noch nicht. Ist aber trotzdem eine ganz schöne
Orgie.
Sowas zu steuern gehört aber meines Erachtens nach in den C++ Standard
und nicht in die Konfiguration des gdb oder wer auch immer.
Hans-Georg L. schrieb:> @Wilhelm M> requires kennt der gcc erst ab version 10.
Bis Du sicher? Auch mit -fconcepts-ts oder -fconcepts? Aber ich weiß es
nicht mehr genau, ab welcher Version, ist schon sooo lange her.
Trotzdem gebe ich Dir den guten Rat, auf eine aktuelle Version des gcc
zu gehen, wenn Du den Weg - der super sinnvoll ist - weiter verfolgen
willst. Denn Concepts sind DAS feature für stat. Polymorphie.
Begreife Klassentemplates als Meta-Funktionen, die Du mit Hilfe von
Concepts durch partielle Spezialisierung "überladen" kannst: Du kannst
also eine Meta-Funktion (partielle Spezialisierung) anhand eines
Concepts für einen template-typ-parameter (oder nttp) aktivieren. Das
ist die statische Analogie zu single-dispatch bzw. zu tag-dispatching.
Hans-Georg L. schrieb:> Beim debugger single step landet er direct in> meinem "set_bit" mit der Einschränkung das ich mir nicht den parameter> pack angucken kann.
Sollte im mangled-name stehen ...
temp schrieb:> Deinen Code oben würde ich nicht mal ansatzweise in Erwägung ziehen.> Alles was nicht mit den Definitionen aus den Headern des Controllers
jeder hat seine Vorlieben ;-)
Wilhelm M. schrieb:> Trotzdem gebe ich Dir den guten Rat, auf eine aktuelle Version des gcc> zu gehen, wenn Du den Weg - der super sinnvoll ist - weiter verfolgen> willst. Denn Concepts sind DAS feature für stat. Polymorphie.>> Begreife Klassentemplates als Meta-Funktionen, die Du mit Hilfe von> Concepts durch partielle Spezialisierung "überladen" kannst: Du kannst> also eine Meta-Funktion (partielle Spezialisierung) anhand eines> Concepts für einen template-typ-parameter (oder nttp) aktivieren. Das> ist die statische Analogie zu single-dispatch bzw. zu tag-dispatching.
Ich habe dem gcc 10.2 von der ARM-Seite auf der Platte und in Eclipse
als User defined Toolchain in eine Liste eintragen können aber es gibt
keine Möglichkeit das zu aktivieren. Und im Moment reicht mir das auch
so wie es ist, die Lib wird auch nicht so bleiben wie sie ist. Was mir
von den neusten Errungenschaften von C++ das Leben leichter macht nehme
ich gerne.
Hans-Georg L. schrieb:> Das mit der Namen-Differenz Header zum Datenblatt stört mich bei der HAL> und der LL.
Wenn es am Ende darauf hinausläuft, alle Registerdefinitionen des
Controllers neu in eine andere Syntax zu pressen, kann ich mir kaum
vorstellen, dass da in überschaubarer Zeit eine halbwegs fehlerfreie Lib
rauskommt. Und wozu? Damit du dann die Fehler in deiner Lib suchst und
nicht mehr im Anwendungsprogramm. Typischer Fall von C++ um jeden Preis.
Und dann noch zusätzlich HAL oder LL. Ich kann nur vermuten, du bist im
akademischen Bereich tätig. Geld verdienen geht damit nicht und wenn
Hobby, dann muss das Hobby darin bestehen LIBs zu bauen.
temp schrieb:> Hans-Georg L. schrieb:>> Das mit der Namen-Differenz Header zum Datenblatt stört mich bei der HAL>> und der LL.>> Wenn es am Ende darauf hinausläuft, alle Registerdefinitionen des> Controllers neu in eine andere Syntax zu pressen, kann ich mir kaum> vorstellen, dass da in überschaubarer Zeit eine halbwegs fehlerfreie Lib> rauskommt.
Das kommt darauf an, woher die ursprünglichen Definitionen kommen. Beim
AVR gibt's z.B. XML-Dateien, die die Register und andere Dinge
beschreiben, aus denen die Header generiert werden. Daraus könnte man
auch entsprechende C++-Header automatisiert generieren.
Rolf M. schrieb:> Das kommt darauf an, woher die ursprünglichen Definitionen kommen.
Vom Hersteller natürlich.
Rolf M. schrieb:> Daraus könnte man> auch entsprechende C++-Header automatisiert generieren.
Auch das macht sich nicht von allein. Ich würde an sowas micht mal einen
Gedanken verschwenden.
Rolf M. schrieb:> temp schrieb:>> Hans-Georg L. schrieb:>>> Das mit der Namen-Differenz Header zum Datenblatt stört mich bei der HAL>>> und der LL.>>>> Wenn es am Ende darauf hinausläuft, alle Registerdefinitionen des>> Controllers neu in eine andere Syntax zu pressen, kann ich mir kaum>> vorstellen, dass da in überschaubarer Zeit eine halbwegs fehlerfreie Lib>> rauskommt.>> Das kommt darauf an, woher die ursprünglichen Definitionen kommen. Beim> AVR gibt's z.B. XML-Dateien, die die Register und andere Dinge> beschreiben, aus denen die Header generiert werden. Daraus könnte man> auch entsprechende C++-Header automatisiert generieren.
Für ARM gibt's dafür sogar Doku:
https://www.keil.com/pack/doc/CMSIS/SVD/html/index.html
temp schrieb:> Rolf M. schrieb:>> Das kommt darauf an, woher die ursprünglichen Definitionen kommen.>> Vom Hersteller natürlich.>> Rolf M. schrieb:>> Daraus könnte man>> auch entsprechende C++-Header automatisiert generieren.
Gibt es beim den ARM MC auch nennt sich svd Files und die werden auch
vom Debugger benutzt um SFR Register an zu zeigen.
>> Auch das macht sich nicht von allein. Ich würde an sowas micht mal einen> Gedanken verschwenden.
Kein Hexenwerk so was ähnliches habe ich schon öfter gemacht. Das macht
aber erst Sinn wenn ich meine Zielstruktur gefunden habe und da bin ich
gerade dabei.
temp schrieb:> Hans-Georg L. schrieb:>> Das mit der Namen-Differenz Header zum Datenblatt stört mich bei der HAL>> und der LL.>> Wenn es am Ende darauf hinausläuft, alle Registerdefinitionen des> Controllers neu in eine andere Syntax zu pressen, kann ich mir kaum> vorstellen, dass da in überschaubarer Zeit eine halbwegs fehlerfreie Lib> rauskommt. Und wozu? Damit du dann die Fehler in deiner Lib suchst und> nicht mehr im Anwendungsprogramm. Typischer Fall von C++ um jeden Preis.> Und dann noch zusätzlich HAL oder LL. Ich kann nur vermuten, du bist im> akademischen Bereich tätig. Geld verdienen geht damit nicht und wenn> Hobby, dann muss das Hobby darin bestehen LIBs zu bauen.
Hättest du nicht nur vermutet und den Thread auch gelesen ...
Aber extra für dich noch einmal. Ich habe lange Zeit meine Brötchen mit
klassischem C++ verdient und bin seit ein paar Jährchen Rentner. Jetzt
beschäftige ich mich eben mit meta-Programmierung weil mir das einfach
Spaß macht.
Hans-Georg L. schrieb:> Jetzt> beschäftige ich mich eben mit meta-Programmierung weil mir das einfach> Spaß macht.
Ist doch kein Problem, wenn du deine Erfüllung darin siehst.
Damit verfolgst du halt andere Ziele als die meisten hier.
> [C]> class GpioPin2> {> public:> GPIO_TypeDef *pPort;> uint8_t pos;>> GpioPin2( GPIO_TypeDef * pP, uint8_t p) { pPort=pP; pos=p;> }> constexpr inline void Set() const { pPort->BSRR=1<<pos; }> constexpr inline void Clr() const { pPort->BSRR=1<<(pos+16); }> };> Auch hier gibt es keinen Weg bei ausgeschalteter Optimierung das gleiche> Ergebnis wie mit dem Macro zu erzeugen.
Ähh doch, siehe: https://godbolt.org/z/KfzexM
Man braucht lediglich always_inline Attribute + lokale O3 Optimierung zu
verwenden, was ich in einem solchen Fall für legitim halten würde.
Der erzeugte Maschinencode ist für beide Funktionen sowohl für O0 als
auch O3 identisch.
Aber dann ist der Maschinencode mit O0 immer noch 2.5 mal so lang ggü.
O3, von daher verstehe ich deine Ansicht nicht so ganz...
Ich werde mal bei ST ein Ticket aufmachen, dass die HAL_GPIO_WritePin
Implementierung in den Header verlegt werden soll.
temp schrieb:> Rolf M. schrieb:>> Das kommt darauf an, woher die ursprünglichen Definitionen kommen.>> Vom Hersteller natürlich.
Entsprechend dem darauf folgenden Beispiel hätte man eigentlich darauf
kommen können, dass gemeint war, ob da wirklich einer den ganzen Header
von Hand geschrieben oder vielleicht auch aus etwas generiert hat, aus
dem man genauso gut den C++-Header generieren kann.
> Rolf M. schrieb:>> Daraus könnte man>> auch entsprechende C++-Header automatisiert generieren.>> Auch das macht sich nicht von allein.
Doch, wenn man einmal den Generator geschrieben hat (was nun auch nicht
arg schwer ist), macht sich das von allein. Dafür sind Code-Generatoren
da. Das machen sie für den C-Code ja auch.
> Ich würde an sowas micht mal einen Gedanken verschwenden.
Ich halte es dagegen für sinnvoll und sehe nichts, was dagegen spricht.
Hans-Georg L. schrieb:> @Wilhelm M> requires kennt der gcc erst ab version 10.
Ich hatte Dir die notwendigen Optionen genannt. Hast Du die eingesetzt?
Im CompilerExplorer mit gcc-9.3 und -std=c++17 -Og -fconcepts
geht das. Sogar ab Version 7.1.
interessant schrieb:> Ähh doch, siehe: https://godbolt.org/z/KfzexM> Man braucht lediglich always_inline Attribute + lokale O3 Optimierung zu> verwenden, was ich in einem solchen Fall für legitim halten würde.>> Der erzeugte Maschinencode ist für beide Funktionen sowohl für O0 als> auch O3 identisch.
Stell deinen Beispielcode als Beweis hier rein oder halt den Mund. Und
nein, always_inline ist leider nicht die Lösung und locale O3
Optimierung auch nicht. Solange du nicht über das Zitieren meines Codes
hinauskommst nehme ich dich nicht für voll.
interessant schrieb:> Der erzeugte Maschinencode ist für beide Funktionen sowohl für O0 als> auch O3 identisch.>> Aber dann ist der Maschinencode mit O0 immer noch 2.5 mal so lang ggü.> O3, von daher verstehe ich deine Ansicht nicht so ganz...
Aha, identischer Maschinencode der 2,5mal länger ist. Fällt dir da
nichts ein?
temp schrieb:>> Ähh doch, siehe: https://godbolt.org/z/KfzexM
Sorry, ich rudere zurück und bitte um Entschuldigung. Den Code im
Onlinecompiler hatte ich nicht gesehen, da bei mir der Link zerst nicht
ging.
temp schrieb:> interessant schrieb:>> Ähh doch, siehe: https://godbolt.org/z/KfzexM>> Man braucht lediglich always_inline Attribute + lokale O3 Optimierung zu>> verwenden, was ich in einem solchen Fall für legitim halten würde.
So, ich hab das natürlich probiert. Deine locale O3 Optimierung bring
leider genau nichts.
Das liegt daran, dass da wo du das notiert hat, kein Code erzeugt wird.
Macht man die locale Optimierung da wo es verwendet wird (aLed.Set()
aLed.Clr()) oder in deinem Beispiel für die gesamte Funktion a() oder
b() geht das. Leider ist das aber keine Option, da ich das Gegenteil
erreichen will. a() oder b() vernünftig debuggen ohne beim Singelstep in
die Internas der Klasse Gpio zu springen.
Es wäre wirklich eine riesen Hilfe, wenn die locale Optimierung auch bei
Headern oder Klassendefinitionen funktionieren würde. Oder noch viel
besser in wenn der Sprachstandard so etwas hergeben würde.
Wilhelm M. schrieb:> Hans-Georg L. schrieb:>> @Wilhelm M>> requires kennt der gcc erst ab version 10.>> Ich hatte Dir die notwendigen Optionen genannt. Hast Du die eingesetzt?>> Im CompilerExplorer mit gcc-9.3 und -std=c++17 -Og -fconcepts> geht das. Sogar ab Version 7.1.
-fconcepts war der Zauberspruch ;-)
-std=c++2a wie zuerst vorgeschlagen, hat nicht funktioniert.
Programmierer schrieb:> Hau wech den Scheiss schrieb:>> Eben. Warum irgendwelche modischen Neuerungen durchdrücken, wenn es>> weder die Manpower dafür gibt, noch irgendwelche Verbesserungen an der>> Sicherheit aka Kundenzufriedenheit zu erwarten sind.>> Worauf bezieht sich das jetzt? Neue Sprachfeatures wie z.B. Lambdas> bedeuten einfachere und schnellere Entwicklung und Wartung, und dadurch> geringere Entwicklungskosten und billigere Endprodukte, und billig macht> Kunden zufrieden.
Ganz ehrlich: was ist der Vorteil von Lambdas. Der Nachteil ist halt
dass die Lambda Funktion nicht einfach als Funktion getestet werden kann
(ohne Copy-Paste), sondern nur im Kontext der verwendeten Funktion.
Minimaler Vorteil ist ein leicht geringerer Schreibaufwand.
lalala schrieb:> Ganz ehrlich: was ist der Vorteil von Lambdas. Der Nachteil ist halt> dass die Lambda Funktion nicht einfach als Funktion getestet werden kann> (ohne Copy-Paste), sondern nur im Kontext der verwendeten Funktion.> Minimaler Vorteil ist ein leicht geringerer Schreibaufwand.
Die Dinger können Variablen aus ihrem Kontext capturen. Wenn man nicht
nur eine Funktion sondern auch noch eine struct mit 4 Variablen oder so
dazu braucht relativiert sich das mit dem "minimal".
lalala schrieb:> Ganz ehrlich: was ist der Vorteil von Lambdas. Der Nachteil ist halt> dass die Lambda Funktion
Lambda-Funktionen gibt es nicht. Was Du meinst, ist eine
Lambda-Expression, die ein closure generiert, vulgo function-object.
Gerade für µC finde ich lambda-expression in der Form als IIFE
(immediate invoked function expression) extrem nützlich, um komplexe
Initialisierungen für read-only Objekte (const) durchzuführen:
1
constautox=[]{
2
// komplexe Berechnung
3
returnresult;
4
}();
Ein einfaches Beispiel das o.g. einzusetzen, ist die Berechung von LUTs.
Oder
1
IrgendeinRegister::on<IrgendeinFlag>([]{
2
// ...
3
});
(inkl. Rücksetzen, o.ä.).
Ansonsten sind die lambda-expressions natürlich überall dort extrem
praktisch, wo man sonst mit Funktionszeigern oder allg.
Funktionsobjekten in Form von expliziten Klassen arbeiten musste (etwa
stdlib-Algos).
lalala schrieb:> Ganz ehrlich: was ist der Vorteil von Lambdas. Der Nachteil ist halt> dass die Lambda Funktion nicht einfach als Funktion getestet werden kann> (ohne Copy-Paste), sondern nur im Kontext der verwendeten Funktion.> Minimaler Vorteil ist ein leicht geringerer Schreibaufwand.
Hauptvorteil ist die deutlich erhöhte Übersichtlichkeit des Code, weil
ich einen Zweizeiler nicht irgendwo weit weg als separate Funktion
definieren muss, nur weil es halt eine Funktion sein muss, sondern
gleich dorthin schreiben, wo er verwendet wird.
Rolf M. schrieb:> Hauptvorteil ist die deutlich erhöhte Übersichtlichkeit des Code, weil> ich einen Zweizeiler nicht irgendwo weit weg als separate Funktion> definieren muss, nur weil es halt eine Funktion sein muss, sondern> gleich dorthin schreiben, wo er verwendet wird.
Das hielt sich eigentlich in Grenzen, weil man ja überall einfach eine
Klasse/struct definieren konnte (auch lokal). Aber solche
Funktionsobjekte selbst zu schreiben war halt doch immer Aufwand.
[code]
void fn() {
// ...
struct S {
S(int someValue) { //bla }
bool operator()(int n) { // bla }
// blub...
};
algorithm(begin, end, S(4));
}
interessant schrieb:>> [C]>> class GpioPin2>> {>> public:>> GPIO_TypeDef *pPort;>> uint8_t pos;>>>> GpioPin2( GPIO_TypeDef * pP, uint8_t p) { pPort=pP; pos=p;>> }>> constexpr inline void Set() const { pPort->BSRR=1<<pos; }>> constexpr inline void Clr() const { pPort->BSRR=1<<(pos+16); }>> };>> Auch hier gibt es keinen Weg bei ausgeschalteter Optimierung das gleiche>> Ergebnis wie mit dem Macro zu erzeugen.>> Ähh doch, siehe: https://godbolt.org/z/KfzexM> Man braucht lediglich always_inline Attribute + lokale O3 Optimierung zu> verwenden, was ich in einem solchen Fall für legitim halten würde.>> Der erzeugte Maschinencode ist für beide Funktionen sowohl für O0 als> auch O3 identisch.>> Aber dann ist der Maschinencode mit O0 immer noch 2.5 mal so lang ggü.> O3, von daher verstehe ich deine Ansicht nicht so ganz...>> Ich werde mal bei ST ein Ticket aufmachen, dass die HAL_GPIO_WritePin> Implementierung in den Header verlegt werden soll.
Wer aus dem Code-Schnippsel tatsächlich alles rausholen will(*)
, der könnte auf das Schieben verzichten und das für's "Löschen"
zuständigen Register BRR benutzen. Zumindest "unoptimiert" ist das
schneller.
Außerdem kann man da auch schön sehen, daß zu wissen, was die HW kann
(oder welchen Algorithmus man verwendet) wichtiger ist, als den
Maschinencode direkt zu schreiben.
(*) auf einem CortexM3 bringt das mit >O0 natürlich nicht wirklich was.
Aber das zu verstehen setzt Kenntnisse des Thumb(2) Befehlssatzes
voraus.
temp schrieb:> So, ich hab das natürlich probiert. Deine locale O3 Optimierung bring> leider genau nichts.Leider ist das aber keine Option, da ich das Gegenteil> erreichen will. a() oder b() vernünftig debuggen ohne beim Singelstep in> die Internas der Klasse Gpio zu springen.
Stimmt, die O3 bringt nichts, aber das always_inline schon.
Dein Problem verstehe ich trotzdem nicht.
Wer zum Geier single stepped seinen gesamten Code?
Wenn da eine Funktion "pinA.set()" steht, wendet man step over an, denn
das ist trivial code den man einmal schreibt und dann nie wieder
debuggt.
Single stepping macht man erst, wenn man verzweifelt einen Hardfault
Fehler sucht :D
lalala schrieb:> Ganz ehrlich: was ist der Vorteil von Lambdas. Der Nachteil ist halt> dass die Lambda Funktion nicht einfach als Funktion getestet werden kann> (ohne Copy-Paste), sondern nur im Kontext der verwendeten Funktion.> Minimaler Vorteil ist ein leicht geringerer Schreibaufwand.
Die Lambda-Ausdrücke kommen ursprünglich aus der funktionalen
Programmierung und finden nach und nach auch Einzug in imperative
Programmiersprachen. In Funktionalsprachen dienen sie primär
dazu,
1. zusammengehörige Dinge im Quellcode näher zusammenzurücken und damit
die Übersichtlichkeit zu steigern
2. für Funktionen, deren Bedeutung auf einen Blick erfasst werden kann,
den Funktionsnamen einzusparen
3. als angenehmen Nebeneffekt den Schreibaufwand zu verringern
Diese Dinge sind aber nur bei sehr einfachen Funktionen relevant.
Funktionen, die mehr als einen Einfachen Ausdruck enthalten, werden
praktisch immer ganz normal mit Namen definiert.
Da C++ keine lokalen Funktionsdefinitionen (also Funktionsdefinitionen
innerhalb einer anderen Funktion) in der klassischen Notation
erlaubt¹, kommt hier noch ein weiterer wesentlicher Aspekt hinzu:
4. Funktionen lokal zu definieren
Dabei geht es nicht nur um die Sichtbarkeitsbeschränkung dieser
Funktionen, sondern vor allem darum, in der lokalen Funktion auf lokale
Variablen der umgebenden Funktion zugreifen zu können. Dazu muss die
lokale Funktion nicht notwendigerweise anonym sein. Möchte man die
Funktion benennen, weist man den Lambda-Ausdruck einfach einer Variable
mit passendem Namen zu:
1
voidouterFunc(intx){
2
constautolocalFunc=[x](inty}{
3
...
4
// do something with x and y
5
...
6
}
7
...
8
localFunc(42);// direct call
9
...
10
otherFunc(localFunc);// use as callback function
11
...
12
}
Aus dem (in C++ local nicht erlaubten) klassischen Funktionskopf
1
voidlocalFunc(inty){
wird also
1
constautolocalFunc=[x](inty}{
was ja gar nicht einmal so viel anders aussieht.
Würde man localFunc global definieren, hätte sie keinen Zugriff auf x.
Man müsste deswegen x als zweites Argument (zusätzlich zu y) übergeben,
was aber insbesondere bei der Verwendung als Callback-Funktion nicht
immer möglich ist, weil sich dadurch die Funktionssignatur ändert.
Alternativ kann man die Funktion in ein callable Object packen:
Al Fine schrieb:> void fn() {> // ...>> struct S {> S(int someValue) { //bla }> bool operator()(int n) { // bla }> // blub...> };>> algorithm(begin, end, S(4));> }
So (oder so ähnlich) werden die Lambda-Ausdrücke intern repräsentiert.
Die [...](...)-Schreibweise ist willkommener syntaktischer Zucker dafür.
Witzigerweise sind wegen des o.g. 4. Punkts Lambda-Ausdrücke in C++ weit
weniger verzichtbar als in den funktionalen Sprachen, in denen sie
ursprünglich implementiert wurden, zumal es dort für viele typische
Anwendungen von Lambda-Ausdrücken Ersatzschreibweisen gibt, die noch
einmal kürzer und prägnanter sind.
──────────────
¹) GCC unterstützt lokale Funktionsdefinitionen als Erweiterung in C,
aber nicht in C++.
Yalu X. schrieb:> So (oder so ähnlich) werden die Lambda-Ausdrücke intern repräsentiert.
Nicht der Lambda-Ausdruck wird so repräsentiert, sondern das Closure,
also das Funktionsobjekt. Also das Ergebnis des Lambda-Ausdrucks.
Carl D. schrieb:> Wer aus dem Code-Schnippsel tatsächlich alles rausholen will(*)> , der könnte auf das Schieben verzichten und das für's "Löschen"> zuständigen Register BRR benutzen. Zumindest "unoptimiert" ist das> schneller.
Beweis das mal.
Das ändert rein garnichts. Das Schieben mit Konstanten erfolgt doch
nicht zur Laufzeit. Das Berechnet der Compiler zur Laufzeit. Und am Ende
bleibt eine Zuweisung eines Registers mit einer Konstannten. Aber diese
Diskussion geht am Ziel vobei. Ich suche nicht nach einer Lösung für
genau das Problem, sondern kritisieren den aktuellen Zustand von C++ in
dieser Hinsicht.
interessant schrieb:> Wer zum Geier single stepped seinen gesamten Code?> Wenn da eine Funktion "pinA.set()" steht, wendet man step over an, denn> das ist trivial code den man einmal schreibt und dann nie wieder> debuggt.>> Single stepping macht man erst, wenn man verzweifelt einen Hardfault> Fehler sucht :D
Wer bestimmt wann man was macht? Du nicht!
Es geht hier ums Prinzip und nicht um dieses konkrete Beispiel. Aber mal
ein Beispiel.
1
voidtestfunc(constchar*p,size_tlen);
2
3
...
4
...
5
constchar*p="Mülleimer";
6
testfunc(p,strlen(p));
7
...
8
std::strings("Mülleimer");
9
testfunc(s.c_str(),s.length());
10
...
wenn ich im Singelstep im ersten Aufruf in testfunc() reinspringe lande
ich auch sofort darin. strlen() ist eine Funktion aus der optimierten
Lib und ich lande niemals in der Sourcen von strlen().
Anders die Variante mit dem std::string. Hier lande ich erst mal in den
Headern davon und muss mich da durch hangeln bis ich irgendwann mal in
der testfunc() lande. Sofort kommen jetzt wieder Schlauschweine die
messerscharf schließen, man kann doch einen Breakpoint in testfunc()
setzen. Alles richtig und wird sicher auch gemacht. Schön ist aber was
anderes. Hinzukommt, eine strlen() bleibt optimiert ob ich das Programm
debugge oder nicht. Wie std::string in Maschinencode übersetzt wird ist
aber vom Optimierungslevel abhängig. Je mehr Metaprogrammiererei in den
C++ Standard-Libs verwendet wird, desto mehr unterscheiden sich die
Debug- und Releasevarianten eines Programms. Für mich ist und bleibt es
ein Rückschritt.
temp schrieb:> Für mich ist und bleibt es> ein Rückschritt.
Du debug-st einfach zuviel ;-) Verwende mehr compiletime-Konstrukte,
Strong-Types, etc, u.s.w. und Deine "Debugging-Experience" wird sich
massiv verändern.
temp schrieb:> Carl D. schrieb:>> Wer aus dem Code-Schnippsel tatsächlich alles rausholen will(*)>> , der könnte auf das Schieben verzichten und das für's "Löschen">> zuständigen Register BRR benutzen. Zumindest "unoptimiert" ist das>> schneller.>> Beweis das mal.> Das ändert rein garnichts. Das Schieben mit Konstanten erfolgt doch> nicht zur Laufzeit. Das Berechnet der Compiler zur Laufzeit.
Wo steht da, daß diese Klasse nur "constexpr" instanziiert werden kann?
Das "constexpr" vor dem Konstruktor sagt nur, daß diese Klasse in
compiletime Code instanziiert werden kann. BTW, das "constexpr" zu
erzwingen heißt (ab C++20) "consteval".
Daß man auf einem M3/4/... das Shiften umsonst bekommt, das ändert nicht
an der Hauptaussage, daß man erst wissen sollte, was man tut und erst
dann die Frage kommt "mit welchem Werkzeug".
Aber was soll's. Jeder wie er will.
Wilhelm M. schrieb:> Du debug-st einfach zuviel ;-) Verwende mehr compiletime-Konstrukte,> Strong-Types, etc, u.s.w. und Deine "Debugging-Experience" wird sich> massiv verändern.
Wenn das alles ist was an Argumenten bleibt hat sich jede weitere
Diskussion erübrigt.
temp schrieb:> Wilhelm M. schrieb:>> Du debug-st einfach zuviel ;-) Verwende mehr compiletime-Konstrukte,>> Strong-Types, etc, u.s.w. und Deine "Debugging-Experience" wird sich>> massiv verändern.>> Wenn das alles ist was an Argumenten bleibt hat sich jede weitere> Diskussion erübrigt.
Das sind äußerst gewichtige Argumente: Code, der nicht compiliert, den
braucht man nicht zu debuggen ;-)
Carl D. schrieb:> Wo steht da, daß diese Klasse nur "constexpr" instanziiert werden kann?> Das "constexpr" vor dem Konstruktor sagt nur, daß diese Klasse in> compiletime Code instanziiert werden kann. BTW, das "constexpr" zu> erzwingen heißt (ab C++20) "consteval".>> Daß man auf einem M3/4/... das Shiften umsonst bekommt, das ändert nicht> an der Hauptaussage, daß man erst wissen sollte, was man tut und erst> dann die Frage kommt "mit welchem Werkzeug".>> Aber was soll's. Jeder wie er will.
Hast du es immer noch nicht kapiert? Ich habe das als simples
nachvollziehbares Beispiel benutzt. Selbst wenn ich das als reales
Problem hätte würde ich mit Sicherheit nicht hier nach einer Lösung
fragen.
Hans-Georg L. schrieb:> Es verbietet niemand, da wo man hin will einen breakpoint zu setzen ;-)
Herr lass Hirn regnen.
So langsam glaube ich, ich bin hier bei selbst ernannten C++ Gurus
gelandet die von sich selbst glauben die Weisheit mit Löffeln gefressen
zu haben. Mann kann das ja auch schön als Schwanzverlängerung verwenden
wenn man sonst irgendwelche Minderwertigkeitskomplexe hat. Und wehe es
kommt einer daher der sich wagt Kritik an dem heiligen Werkzeug zu
äussern...
Ich bin jetzt raus hier.
temp schrieb:> Wilhelm M. schrieb:>> Du debug-st einfach zuviel ;-) Verwende mehr compiletime-Konstrukte,>> Strong-Types, etc, u.s.w. und Deine "Debugging-Experience" wird sich>> massiv verändern.>> Wenn das alles ist was an Argumenten bleibt hat sich jede weitere> Diskussion erübrigt.
Er macht nur, was vorher mit seinen zig anderen Argumenten dafür von der
Gegenseite gemacht wurde.
Ja, der Gegenstand der Diskussion hat Nachteile zu anderen, aber eben
auch viele Vorteile, die diese Nachteile überwiegen könnte, um es
wertfrei zu schreiben.
Und weniger debuggen durch besser Typprüfung ist ein solcher "andere
Nachteile überwiegender Vorteil".
temp schrieb:> Und wehe es> kommt einer daher der sich wagt Kritik an dem heiligen Werkzeug zu> äussern...> Ich bin jetzt raus hier.
Ja, dann, dann, dann ... dann entziehst Du Dich der Diskussion. Viel
Spaß beim debuggen ;-)
temp schrieb:
...
> Beweis das mal.> Das ändert rein garnichts. Das Schieben mit Konstanten erfolgt doch> nicht zur Laufzeit. Das Berechnet der Compiler zur Laufzeit. Und am Ende
Eher: Das Berechnet der Compiler zur Übersetzungszeit.
Ihr macht ja schon Sublimationsfehler. Das ist dann, wenn das Gehirn als
Dampf durch die Ohren austritt.
Hitzige Diskussion, was? Dabei sind doch neue Features was sehr schönes.
Besonders wenn niemand einen zwingt sie zu benutzen:P
Jedzia D. schrieb:> temp schrieb:> ...>> Das Berechnet der Compiler zur Laufzeit.> Eher: Das Berechnet der Compiler zur Übersetzungszeit.
Was das gleiche ist: Du hast den Satz vielleicht nicht aufmerksam
gelesen.
Und wenn män es klarer schreiben will: Das berechnet der Compiler.
(Punkt)
temp schrieb:> Und nein, always_inline ist leider nicht die Lösung und locale O3> Optimierung auch nicht.
Optimierung und always_inline haben Einfluß auf Optimierung, aber nicht
auf die Erzeugung von Debug-Info.
Was in die Richtung geht wäre Attribut "artificial", vielleicht hilft
das ja?