Hi Community! - Welche engl. oder deutsche Literatur könnt ihr empfehlen zum Umstieg von C auf C++? Dies können Bücher (engl., deutsch), Websites oder PDFs sein. Anwendungsgebiet ist die Entwicklung von Software auf der Kommandozeile in Linux oder Windows. Bisher habe ich das Buch und den gleichnamigen Kurs von Ira Pohl gefunden. Meinungen? Das Kursmaterial https://www.coursera.org/learn/c-plus-plus-a ist irgendwie nicht zu erhalten, obwohl sie es schreiben. - Erwünscht ist (zudem) die Diskussion auf Assembler-Ebene der grundlegenden Features (Konstruktoren, Referenzen, "new/delete", Klassen und Vererbung, evtl. exceptions, etc.). Oder: Mit welchen Features verlässt man den Compiler-Bereich und es wird Assembler-Code erzeugt, der sich von C unterscheidet? Ich denke, einfache Klassen an sich provozieren keinen (oder minim) unterschiedlichen Code gegenüber C-structs? Bestenfalls sollte in der Diskussion bzw. Analyse der x86/x86-64-Befehlssatz in Intel-Syntax (!) verwendet worden sein. Falls es im Mikrocontroller-Bereich derartige Literatur gibt, darf nur der AVR 8-bit-Befehlssatz referenziert werden. Freundliche Grüsse Microwave89
:
Verschoben durch User
Zur Sprache selbst würde ich The C++ Programming Language vom Erfinder der Sprache empfehlen. Gibt's auch auf Deutsch, aber ich weiß nicht, ob das was taugt. Jonas S. schrieb: > - Erwünscht ist (zudem) die Diskussion auf Assembler-Ebene der > grundlegenden Features (Konstruktoren, Referenzen, "new/delete", Klassen > und Vererbung, evtl. exceptions, etc.). Wie das implementiert ist, ist compiler- und plattformspezifisch. Warum glaubst du, dass das für das Erlernen der Sprache wichtig ist? > Oder: Mit welchen Features verlässt man den Compiler-Bereich und es wird > Assembler-Code erzeugt, der sich von C unterscheidet? Was meinst du "verlässt man den Compiler-Bereich"? C und C++ sind verschiedene Sprachen, natürlich generieren die Compiler unterschiedlichen Code. Dadurch verlässt man aber nicht irgendeinen Bereich. > Ich denke, einfache Klassen an sich provozieren keinen (oder minim) > unterschiedlichen Code gegenüber C-structs? Das hängt davon ab, was "einfache Klassen an sich" sein sollen. Wenn du PODs meinst, dann hast du wahrscheinlich recht. Sobald aber Konstruktoren, Vererbung, Polymorphie u.s.w. dazukommen, sieht's ganz anders aus.
Jonas S. schrieb: > Hi Community! > > - Welche engl. oder deutsche Literatur könnt ihr empfehlen zum Umstieg > von C auf C++? > Dies können Bücher (engl., deutsch), Websites oder PDFs sein. > Anwendungsgebiet ist die Entwicklung von Software auf der Kommandozeile > in Linux oder Windows. Wie wäre es damit: http://mozart.informatik.fh-kl.de/download/Lehre/WS1617/Prog2/Vorlesung/doc/ppcP9000.html
Allgemein: Danke für die schnellen Antworten, komme erst jetzt dazu, zu antworten. Rolf M. schrieb: > Warum > glaubst du, dass das für das Erlernen der Sprache wichtig ist? Es hilft mir beim Erlernen und korrekten Anwenden, wenn ich verstehe, wie ich mir x und y auf C- bzw. Assembler-Ebene vorstellen muss. Ausserdem möchte ich immer gerne verstehen, wie etwas unter der Haube funktioniert. Rolf M. schrieb: > Was meinst du "verlässt man den Compiler-Bereich"? Also welche Features erzeugen von C deutlich verschiedenen Maschinencode? Eben - Bei einer einfachen Klasse (ich weiss gerade (noch) nicht, was POD ist) mit Gettern und Settern aber ohne Kon-/Destruktoren kann ich mir vorstellen, dass grundsätzlich ähnlicher Code erzeugt wird wie für ein C-struct mit u.a. Funktionszeigern darin. "new" und "delete" allozieren intern irgendwo/-wie Speicher, z.B. mit malloc. Bei Konstruktoren bzw. Destruktoren wird eine C-ähnliche Entsprechung in Assembler/Maschinencode schon schwierig. Für mich wäre das wie eine Funktion, die sich nicht an eine Standard-ABI hält, weil es da ja nicht mal ein "void" als Rückgabe gibt. Und dann richtig schwer - wie muss ich mir z.B. die &-Referenzen vorstellen? Ich kenne nur
1 | void foo(int bar){} |
2 | void foo2(int* bar){} |
3 | ...
|
4 | foo(789); |
5 | foo(&blah); |
, was ich mir zumindest in x86(-64)-Assembler gut vorstellen kann. Wie soll jedoch
1 | void foo(int &bar){} |
in Assembler aussehen? Ich kann die Funktion noch nicht einmal auswendig aufrufen... :/ Ihr "müsst" die Fragen nicht ohne Not beantworten, sie sollen aber die Richtung zeigen, in die ich stutzig werde und Literaturtipps wünsche. Rolf M. schrieb: > Sobald aber > Konstruktoren, Vererbung, Polymorphie u.s.w. dazukommen, sieht's ganz > anders aus. Exakt dies dachte ich. Wahrscheinlich ist die beste Lösung erstmal, den Output des Compilers (und Linkers) bei einem einfachen aber klar objektorientierten Programm zu disassemblieren. Raoul D. schrieb: > Wie wäre es damit: > > http://mozart.informatik.fh-kl.de/download/Lehre/WS1617/Prog2/Vorlesung/doc/ppcP9000.html Habe nicht wirklich hineingeschaut, aber da steht eher etwas von Java-Umstieg, und das ist bei mir schon länger her... ;) Grüsse - Microwave
Wenn Du C++ lernen möchtest, dann möchtest Du offensichtlich klassisch OOP lernen oder generische Programmierung - irgendetwas anderes besonderes an C++? Prozedural kannst Du ja schon, weil Du von C kommst. Daher würde ich mich auch damit beschäftigen, und die Assembler-Umsetzung (zunächst) ausser acht lassen. Erst wenn Du das verstanden hast, dann gehe an die Details ...
Guck Dir mal den "C++ Primer" an. Das ist ein gutes, allgemeines Buch. Aktuell ist die fünfte Auflage und es gibt das in Deutsch und Englisch.
Jonas S. schrieb: > Rolf M. schrieb: >> Warum >> glaubst du, dass das für das Erlernen der Sprache wichtig ist? > > Es hilft mir beim Erlernen und korrekten Anwenden, wenn ich verstehe, > wie ich mir x und y auf C- bzw. Assembler-Ebene vorstellen muss. Das hilft nicht, vergess es einfach ganz schnell. Ich unterstelle dir jetzt einfach (nicht böse gemeint, sondern realistisch), dass du (genauso wie selbst die meisten professionellen Programmierer) schon den Befehlssatz einer einigermaßen aktuellen CPU nicht mehr sinnstiftend verstehen. Du möchtest mit C++ eine sehr leistungsfähige Programmiersprache lernen. Dafür gibts sehr gute Compiler, die mehr von Assembler verstehen, als du :-) Was hilft: Mach dir klar, wo und wie Code erzeugt wird. > Ausserdem möchte ich immer gerne verstehen, wie etwas unter der Haube > funktioniert. Das wiederum ist ja legitim. Aber dazu brauchts kein Assembler. > > Rolf M. schrieb: >> Was meinst du "verlässt man den Compiler-Bereich"? > > Also welche Features erzeugen von C deutlich verschiedenen > Maschinencode? > Eben - Bei einer einfachen Klasse (ich weiss gerade (noch) nicht, was > POD ist) Plain-old-data. Im Prinzip das, was eine struct in C ist/war. > mit Gettern und Settern C++ kenn keine Getter und Setter. > aber ohne Kon-/Destruktoren kann ich > mir vorstellen, dass grundsätzlich ähnlicher Code erzeugt wird wie für > ein C-struct mit u.a. Funktionszeigern darin. Nein, wozu auch? Bei einer einfachen Klasse gibt es nicht die geringste Notwendigkeit für Funktionszeiger. Der Compiler wird nach wie vor einfache Funktionen erzeugen, die dann vom Linker zur Compilezeit fest zusammengebunden werden. Fertig. Wenn du magst, stell dir vor, dass diese Funktionen als unsichtbares Argument immer den "this"-Zeiger haben. Der Vergleich mit der C-Struktur mit Zeigern drin ist schwierig. In C ist das eine Krücke, weil man quasi die "Methoden" zum "Objekt" packen möchte. In C++ macht das im Normalfall nach wie vor der Linker zur Compilezeit. Erst bei Vererbung von Klassen kann man in C++ fordern, dass Funktionen eben nicht zur Compilezeit gebunden werden, sondern erst zur Laufzeit. Das nennt man dort "virtuelle Methode". Und für solche wird dann tatsächlich eine kleine Struktur mit Funktionszeigern angelegt, die sich gemeinhin "vtable" nennt. > "new" und "delete" > allozieren intern irgendwo/-wie Speicher, z.B. mit malloc. Ja, die haben i.d.R. sogar irgendwo eine Implementierung. > Bei Konstruktoren bzw. Destruktoren wird eine C-ähnliche Entsprechung in > Assembler/Maschinencode schon schwierig. Für mich wäre das wie eine > Funktion, die sich nicht an eine Standard-ABI hält, weil es da ja nicht > mal ein "void" als Rückgabe gibt. Warum? Der Konstruktor ist einfach nur eine Funktion mit "void als Rückgabe", wie du es schreibst. Auch diese Funktion kriegt, wenn du so magst, als erstes Argument "this" übergeben und soll dann zusehen, wie sie "this" sinnvoll initialisiert. Der Speicher, auf den "this" zeigt, wurde zuvor ja schon vom new-Operator angefordert. > Und dann richtig schwer - wie muss ich mir z.B. die &-Referenzen > vorstellen? > Ich kenne nurvoid foo(int bar){} > void foo2(int* bar){} > ... > foo(789); > foo(&blah);, was ich mir zumindest in x86(-64)-Assembler gut vorstellen > kann. > Wie soll jedochvoid foo(int &bar){}in Assembler aussehen? Ich kann die > Funktion noch nicht einmal auswendig > aufrufen... :/ Warum nicht? Es ist völlig wurscht, wie der Compiler eine Referenz übersetzt. Eine Referenz ist nur ein zweiter Name für ein Objekt. In vielen Fällen könntest du das sogar durch ein prähistorisches Präprozessormakro (#define) ersetzen. > Rolf M. schrieb: >> Sobald aber >> Konstruktoren, Vererbung, Polymorphie u.s.w. dazukommen, sieht's ganz >> anders aus. > > Exakt dies dachte ich. Wahrscheinlich ist die beste Lösung erstmal, den > Output des Compilers (und Linkers) bei einem einfachen aber klar > objektorientierten Programm zu disassemblieren. Das ist eine ziemlich absurde Idee. Welchen Erkenntnisgewinn versprichst du dir denn davon? Ich meine, du kannst ja gerne dem Optimierer beim Arbeiten zugucken und wirst alsbald feststellen, dass der Optimierungen kennt und anwendet, die du auch nach drei Flaschen Lambrusco noch nicht nachvollziehen kannst :-) Du wirst feststellen, dass der Linker immer noch genauso linkt, wie früher. Nur die Namen der Funktionen sehen etwas anders aus, weil wegen der Überladungen noch eine Signatur dazukommt. Das passiert unter dem Arbeitstitel "name mangling". Les doch einfach mal Wikipedia-Artikel zu einigen Stichworten in meiner Antwort. Wenn du ja schon Hintergrund in C hast, sollte das dir einen Überblick verschaffen.
Jonas S. schrieb: > Allgemein: Danke für die schnellen Antworten, komme erst jetzt dazu, zu > antworten. > > Rolf M. schrieb: >> Warum >> glaubst du, dass das für das Erlernen der Sprache wichtig ist? > > Es hilft mir beim Erlernen und korrekten Anwenden, wenn ich verstehe, > wie ich mir x und y auf C- bzw. Assembler-Ebene vorstellen muss. > Ausserdem möchte ich immer gerne verstehen, wie etwas unter der Haube > funktioniert. Die Idee einer Hochsprache ist aber gerade, dass man das nicht braucht. Ich würde dir empfehlen, dich erstmal nur auf der C++-Ebene zu bewegen, und wenn du verstanden hast, wie die Sprache funktioniert und zwecks Optimierung genauer bescheid wissen willst, dann tu das danach. Das Problem wird auch sein, dass du die modernen aggressiven Optimizer das, was generiert wird, für Menschen recht schwer verständlich wird. Und schaltet man den Optimizer aus, hat man keine realistische Einschätzung mehr. > Rolf M. schrieb: >> Was meinst du "verlässt man den Compiler-Bereich"? > > Also welche Features erzeugen von C deutlich verschiedenen > Maschinencode? Wie gesagt: Das hängt sehr vom Compiler ab, auch wenn es einige "gängige" Implementationen gibt. Früher(tm) haben C++-Compiler C-Code generiert. Heute erzeugen sie aber in der Regel direkt Assembler-Code, weil das besseres Optimierungspotenzial bietet. Ich glaube Comeau C++ kann noch nach C konvertieren, kostet aber was und ist anscheinend seit 2013 nicht mehr sonderlich aktiv. > Eben - Bei einer einfachen Klasse (ich weiss gerade (noch) nicht, was > POD ist) "plain old data", also etwas, das im Prinzip genauso wie eine C-Struktur aufgebaut ist. Bekommt man, wenn die Klasse keine Kontruktoren und keinen Destruktor hat, keine Basisklassen, keine Member-Variablen, die selbst nicht POD sind und keine virtuellen Memberfunktionen. > mit Gettern und Settern aber ohne Kon-/Destruktoren kann ich > mir vorstellen, dass grundsätzlich ähnlicher Code erzeugt wird wie für > ein C-struct mit u.a. Funktionszeigern darin. Nein, Funktionszeiger werden da nicht angelegt. Nur die Variablen sind enthalte und bei virtuellen Memberfunktionen ein oder mehrere Vtable-Zeiger. > "new" und "delete" allozieren intern irgendwo/-wie Speicher, z.B. mit > malloc. Ja, allerdings wirft new eine Exception, wenn kein Speicher mehr da ist. > Bei Konstruktoren bzw. Destruktoren wird eine C-ähnliche Entsprechung in > Assembler/Maschinencode schon schwierig. Für mich wäre das wie eine > Funktion, die sich nicht an eine Standard-ABI hält, weil es da ja nicht > mal ein "void" als Rückgabe gibt. Da wird noch einiges außenrum gemacht. Schließlich müssen auch die Konstruktoren / Destruktoren der Basisklassen und Membervariablen aufgerufen und verschiedene weitere Initialisierungen gemacht werden. > Und dann richtig schwer - wie muss ich mir z.B. die &-Referenzen > vorstellen? Die sind das einfachste. Die Compiler, die ich kenne, implementieren das unter der Haube einfach genau wie Zeiger. > Rolf M. schrieb: >> Sobald aber >> Konstruktoren, Vererbung, Polymorphie u.s.w. dazukommen, sieht's ganz >> anders aus. > > Exakt dies dachte ich. Wahrscheinlich ist die beste Lösung erstmal, den > Output des Compilers (und Linkers) bei einem einfachen aber klar > objektorientierten Programm zu disassemblieren. Wie gesagt: Ich halte es für wenig sinnvoll, so vorzugehen. C++ selbst ist schon schwierig genug, da muss man sich nicht zusätzlich auch noch aufhalsen, den erzeugten Code verstehen zu wollen.
Die "Für Dummies"-Bücher sind immer gut :-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.