OOC mit Macros, Events, Listen und Exceptions



  • ;fricky schrieb:

    Ad aCTas protest zum trotz: nimm keinesfalls C++

    Keine Sorge, das wird nicht passieren, ich beherrsche schon Java und eine weitere, auf objektorientierter Syntax aufgebauter Sprache, wollte ich ehrlich gesagt nicht lernen. 😉

    Gefrickel-Vernichter schrieb:

    Wenn man sich Gedanken darüber macht, Exceptions und OOP in C nachzubauen, ist C++ definitiv die bessere Wahl. Gerade wenn man von Java kommt und sowieso Mühe mit einigen Konzepten hat (manuelle Speicherverwaltung), kann man sich bei C++ wenigstens einen Teil der Arbeit durch RAII abnehmen lassen, während bei C wirklich alles von Hand freigegeben werden muss. Gleiches gilt für andere Konzepte, z.B. Vererbung, Polymorphie, Generics, Collections, und so weiter. Da ist man mit C++ um Lichtjahre näher bei Java.

    Ich finde, dass man hier sehr stark unterscheiden muss, zwischen Features, die mir die Arbeit deutlich erleichtern (new- und delete-Funktionen als De- und Konstruktoren) und Features die nur dazu da sind den Code objektorientierter aussehen zu lassen (wie Exceptions). Erstere halte ich für unabdingbar um vernünftig lesbaren Code produzieren zu können. Es erklärt sich von selbst, dass der Aufruf einer new-Funktion verständlicher ist als deren Inhalt in die aufrufende Funktion zu schreiben. Exceptions wollte ich deshalb haben, weil ich sie sehr nützlich sind um auf unvorhergesehene Fehler zu reagieren - der Aufwand sie zu implementieren ist allerdings sehr hoch und lang nicht so intuitiv wie eine new-Funktion.

    Ich halte es nicht für sinnvoll nur deshalb auf eine objektorientierte Sprache zu setzen, weil einem der Compiler hier zusätzliche Arbeit - wie Speicher zu allokieren - abnimmt. Exceptions sind sicherlich ein Grund eine solche Sprache zu nutzen. Konstuktoren sind dagegen so einfach zu realisieren, dass auf diese mit Sicherheit nicht nur in OO-Sprachen gesetzt werden sollte. Gerade in Bezug auf Libraries versuche ich immer abzuwägen in wie weit es sinnvoll ist Features zu implementieren, die dem Benutzer ermöglichen sich nicht um nervigen aber leider notwendigen Kleinkram wie beispielsweise der Speicherverwaltung zu kümmern.

    Ich finde die Diskussionen ob man beispielsweise nun C, C++, Java oder sonst eine Sprache einsetzen soll z.T. sehr lächerlich, da alle Sprachen komplett unterschiedliche Einsatzgebiete haben. Computerspielentwicklung mag mit C++ u.U. einfacher sein, da mir mit der OO-Syntax viel Arbeit abgenommen wird. Ich entwickle selbst gerade ein kleines 3D-Spiel mit OpenGL, werde dafür aber kein C++ nehmen, da ich an sich nicht an der Entwicklung eines Computerspiels sondern viel mehr an der Entwicklung der 3D-Engine interessiert bin. Das Spiel dient mir nur dazu die Möglichkeiten der Engine an einem Beispiel präsentieren zu können. Mich fasziniert an C nun mal, dass hier eben ganz klar im Vordergrund steht wie etwas funktioniert. Dieses Wissen bräuchte ich beispielsweise nicht wenn ich Direct3D einsetzen würde - hier stehen die Objekte im Vordergrund und eben deren geschicktester Zusammenbau. Im Gegensatz dazu würde ich niemals auf die Idee kommen einen Webserver mit C zu realisieren. Ich interessiere mich zwar stark dafür wie die Daten übers Internet versendet werden und bin gerade auch dabei einen Miniwebserver mit ASM zu programmieren - aber es ist deshalb absoluter Blödsinn Java nicht zu benutzen um eine richtige Webserverapplikation zu programmieren, nur weil ich dann nicht weiß wie das alles hardwareseitig abläuft. Ich hab schließlich keine fünf Jahre Zeit so etwas in C zu realisieren wenn es in Java innerhalb von ein paar Tagen geht. Hier gilt dann (wie auch für C++ und andere OO-Sprachen): Der Aufwand steht ganz klar im Vordergrund.

    Gefrickel-Vernichter schrieb:

    Der Code im ersten Beispiel zeigt bereits, dass 1:1 aus Java übernommen wurde und nirgends ein free() vorkommt. So hat man schneller Memory Leaks als man denkt.

    Hier habe ich bewusst keine Funktionen aufgerufen, die den allokierten Speicher wieder freigeben. Zum einen weil dort das Programm sowieso zu Ende war (beim terminieren des Prozesses wird der Speicher sowieso freigegeben), zum Anderen, weil cih wie bereits gesagt es für sinnvoll halte, dass solche Dinge im Hintergrund ablaufen (in meinem Java Programm wurde mit der Methode start() beispielsweise eine Endlosschleife aufgerufen, die erst beim Schließen des Programms wieder verlassen wurde. Vor dem terminieren des Prozesses wurden aber essentielle Methoden aufgerufen, die eben alles erledigt hatten was es noch vor dem Beenden zu erledigen gibt).

    Hmm, jetzt hab ich hier so einen Mammutbeitrag verfasst, ich hoffe den liest überhaupt jemand durch. 😮



  • Hmm, jetzt hab ich hier so einen Mammutbeitrag verfasst, ich hoffe den liest überhaupt jemand durch.

    Ich hab's gelesen. Aufmerksamkeit erkauft man sich durch das richtige Setzen von Satzzeichen -- schlimm dass es soweit gekommen ist.

    Keine Sorge, das wird nicht passieren, ich beherrsche schon Java und eine weitere, auf objektorientierter Syntax aufgebauter Sprache, wollte ich ehrlich gesagt nicht lernen.

    Da bist du im ANSI-Forum in guter Gesellschaft. Nicht jeder hier mag C++.
    🙂

    Btw würde mich interessieren, ob Objektorientierung wirklich nur Syntax-Sache ist. Könnte eine lustige Diskussion in RudP werden.

    Features die nur dazu da sind den Code objektorientierter aussehen zu lassen (wie Exceptions)

    Da bin ich drüber gestolpert, ich dachte immer, dass Exceptions wirklich was bringen, wenn man aus verschachtelten Aufrufen springen will. Aber da kommt's darauf an, was man meint, wenn man sagt: nur anders aussehen. Wenn man's völlig neu schreibt, sieht's auch nur anders aus.

    Jedenfalls wirst du in allen Fällen, wo du einfach nur aus dem dynamischen Kontext springen willst, mit man: longjmp genauso gut fahren.

    Wenn du magst, kannst du mir Beispiele für die Fälle geben, wo dir Exceptions abgehen, und ich will sehen, wie gut ich das ohne hinkriege.

    Hier habe ich bewusst keine Funktionen aufgerufen, die den allokierten Speicher wieder freigeben. Zum einen weil dort das Programm sowieso zu Ende war (beim terminieren des Prozesses wird der Speicher sowieso freigegeben), zum Anderen, weil cih wie bereits gesagt es für sinnvoll halte, dass solche Dinge im Hintergrund ablaufen

    Ich würde mich nicht darauf verlassen, dass der Speicher freigegeben wird, und der Standard besteht sicher darauf, dass free() aufgerufen wird. Ich kann mich da an einen subtilen Bug hier aus dem Forum erinnern, der mit fehlenden free's zu tun hatte und bei jedem OS/Compiler ein anderes Verhalten provoziert hat. War schwer zu finden, und ist schwer zu erinnern. Deshalb nimm mir bitte den Dogmatismus nicht übel, er kommt aus Erfahrung:

    Satz: Zu jedem malloc() muss ein free(), ohne Ausnahme.



  • Antoras schrieb:

    Exceptions wollte ich deshalb haben, weil ich sie sehr nützlich sind um auf unvorhergesehene Fehler zu reagieren

    das tun sie ja eigentlich nicht. du musst exceptions bewusst werfen, wenn du irgendwo eine fehlerquelle vermutest. bei unvorhersehbaren fehlern würdest du natürlich keine exception losschiessen, weil du ja garnicht erst darauf kommst, dass hier ein fehler auftreten könnte.

    Antoras schrieb:

    Mich fasziniert an C nun mal, dass hier eben ganz klar im Vordergrund steht wie etwas funktioniert.

    mich auch, und dass man vieles direkt und ohne ballast umsetzen kann. du kannst unmittelbar am code ablesen, was passieren wird. es wird nichts versteckt und es gibt keine heimlichen performance-bremsen und speicherfresser. das macht C zur ersten wahl bei hardwarenaher programmierung (naja, oder assembler, je nachdem...).

    Antoras schrieb:

    Im Gegensatz dazu würde ich niemals auf die Idee kommen einen Webserver mit C zu realisieren. Ich interessiere mich zwar stark dafür wie die Daten übers Internet versendet werden und bin gerade auch dabei einen Miniwebserver mit ASM zu programmieren.

    wie jetzt? einen webserver willste nicht in C aber in asm machen? das halte ich für keine gute idee. ok, wenn du spass daran hast, dann mach es, aber C finde ich gerade für sowas wie (embedded) webserver ideal. auch kannste C-code leichter auf andere targets portieren, was mit ASM nur geht, wenn der andere controller auf derselben CPU-familie basiert.

    µngbd schrieb:

    Da bist du im ANSI-Forum in guter Gesellschaft. Nicht jeder hier mag C++.

    ach? wirklich? *frech_grins*

    µngbd schrieb:

    Btw würde mich interessieren, ob Objektorientierung wirklich nur Syntax-Sache ist. Könnte eine lustige Diskussion in RudP werden.

    da gabs da alles schon viele male, blätter mal durch. OOP ist natürlich nicht sprachabhängig, nur isses mit sprachen einfacher zu realisieren, die's direkt unterstützen. es gibt aber auch einige beispiele, wobei OO in nicht-OO-sprachen erfolgreich umgesetzt wurde (GTK, windows-kernel, beides wurde in C geschrieben). andere beispiele sind grafische tools, die aus UML-diagrammen c-code erzeugen können: http://publib.boulder.ibm.com/infocenter/rsdp/v1r0m0/topic/com.ibm.help.download.rhapsody.doc/pdf/tutorialc.pdf

    µngbd schrieb:

    Deshalb nimm mir bitte den Dogmatismus nicht übel, er kommt aus Erfahrung:
    Satz: Zu jedem malloc() muss ein free(), ohne Ausnahme.

    wer dogmen anbringt, kriegt auch gleich 'ne exception vorgesetzt. lies pointercrashs postings hier: http://www.c-plusplus.net/forum/viewtopic-var-t-is-248648-and-start-is-33.html
    🙂



  • fricky schrieb:

    wer dogmen anbringt, kriegt auch gleich 'ne exception vorgesetzt.

    Hehe. Ich will versuchen, das Dogma zu retten:
    Satz: Zu jedem malloc() muss ein free(), ausser die Welt geht gerade unter.

    Antoras schrieb:

    Konstuktoren sind dagegen so einfach zu realisieren, dass auf diese mit Sicherheit nicht nur in OO-Sprachen gesetzt werden sollte.

    Ich hab's mir nocheinmal angesehen:

    GLDisplay *display = newGLDisplay("TestProject");
        TestRenderer *renderer = newTestRenderer();
        InputHandler *handler = newInputHandler(renderer, display);
    

    So ganz hat man damit noch keine Konstruktoren wie in Java, weil die dort etwas erzeugen, was von selbst wieder verschwindet. Wenn aber zB newGLDisplay() Aufrufe von malloc() enthält, solltest du dich, wie das Dogma befiehlt, auf free() einstellen.

    Wie du dafür sorgst, dass free() aufgerufen wird, ist aber völlig dir überlassen. Du könntest zB eine Liste mit Zeigern auf alle allozierten Blöcke unterhalten, um am Ende den Speicher automatisch freigeben zu können. Da würde es dann reichen, am Ende von main zu sagen: free_all(liste) .



  • µngbd schrieb:

    Hehe. Ich will versuchen, das Dogma zu retten:
    Satz: Zu jedem malloc() muss ein free(), ausser die Welt geht gerade unter.

    Wenn wir schon dabei sind, dann
    Satz: Zu jeden malloc() muss ein free() , sonst geht die Welt unter. 😉

    µngbd schrieb:

    Antoras schrieb:

    Konstuktoren sind dagegen so einfach zu realisieren, dass auf diese mit Sicherheit nicht nur in OO-Sprachen gesetzt werden sollte.

    Ich hab's mir nocheinmal angesehen:

    GLDisplay *display = newGLDisplay("TestProject");
        TestRenderer *renderer = newTestRenderer();
        InputHandler *handler = newInputHandler(renderer, display);
    

    So ganz hat man damit noch keine Konstruktoren wie in Java, weil die dort etwas erzeugen, was von selbst wieder verschwindet. Wenn aber zB newGLDisplay() Aufrufe von malloc() enthält, solltest du dich, wie das Dogma befiehlt, auf free() einstellen.

    Wie du dafür sorgst, dass free() aufgerufen wird, ist aber völlig dir überlassen. Du könntest zB eine Liste mit Zeigern auf alle allozierten Blöcke unterhalten, um am Ende den Speicher automatisch freigeben zu können. Da würde es dann reichen, am Ende von main zu sagen: free_all(liste) .

    Nur weil es "automatisch" (wie in Java/C++) nicht geht, heißt es nicht, dass sie nicht Konstruktoren sind. Sie reservieren Speicher, initialisieren das Objekt, sprich sie erledigen die Arbeit eines Konstruktors, somit sind sie auch Konstruktoren. Ein beliebter Fehler bei OO ist es zu glauben, dass bei OO alles "automatisch" gehen muss.

    Und was das free angeht, so kannst du den Code auch weiter vervollständigen:

    GLDisplay *display = newGLDisplay("TestProject");
    TestRenderer *renderer = newTestRenderer();
    InputHandler *handler = newInputHandler(renderer, display);
    
    ...
    
    free_InputHeandler(handler);
    free_TestRenderer(renderer);
    free_GLDisplay(display);
    

    wo ist dann das Problem? Und wenn du dir das sparen willst, dann kannst du dir einen mini-garbage collector für deine Objekte mit man: atexit(3) basteln.



  • supertux schrieb:

    µngbd schrieb:

    Satz: Zu jedem malloc() muss ein free(), ausser die Welt geht gerade unter.

    Satz: Zu jeden malloc() muss ein free() , sonst geht die Welt unter. 😉

    es gibt mindestens eine welt, in der zu jedem malloc() ein free gehört().
    🙂



  • supertux schrieb:

    Wenn wir schon dabei sind, dann
    Satz: Zu jeden malloc() muss ein free() , sonst geht die Welt unter. 😉

    Satz: Zu jedem free() gehört ein malloc() , sonst geht die Welt wirklich unter.



  • +gjm+ schrieb:

    supertux schrieb:

    Wenn wir schon dabei sind, dann
    Satz: Zu jeden malloc() muss ein free() , sonst geht die Welt unter. 😉

    Satz: Zu jedem free() gehört ein malloc() , sonst geht die Welt wirklich unter.

    Ihr seid sicher, daß die Welt malloc() und free() braucht, um nicht unterzugehen? Wenns nicht mehr braucht ... Cool! 🕶

    atexit kannte ich übrigens noch nicht ... man lernt nie aus ... 😉



  • +gjm+ schrieb:

    Satz: Zu jedem free() gehört ein malloc() , sonst geht die Welt wirklich unter.

    also stimmt es doch, was ich immer gegelaubt habe, dass unsere welt erst seit wenigen sekunden existiert.
    🙂



  • also stimmt es doch, was ich immer gegelaubt habe, dass unsere welt erst seit wenigen sekunden existiert.

    Witzig, das hab ich auch schon öfter gedacht. Aber irgendwie müßig, darüber nachzudenken.
    🙂

    atexit kannte ich übrigens noch nicht ... man lernt nie aus ...

    Ich hatte das für eine POSIX-Sache gehalten, aber atexit(3) sagt, daß es schon in C89 vorhanden war. Hätte ich schon öfter verwenden sollen... 🙄



  • µngbd schrieb:

    Ich hatte das für eine POSIX-Sache gehalten, aber atexit(3) sagt, daß es schon in C89 vorhanden war. Hätte ich schon öfter verwenden sollen... 🙄

    Jaa, ich hab auch gestaunt, aber ein paar meiner embedded- compiler kennen das nicht, da wird's das wiederentdeckte goto tun müssen ...
    🙄



  • pointercrash() schrieb:

    µngbd schrieb:

    Ich hatte das für eine POSIX-Sache gehalten, aber atexit(3) sagt, daß es schon in C89 vorhanden war. Hätte ich schon öfter verwenden sollen...

    Jaa, ich hab auch gestaunt, aber ein paar meiner embedded- compiler kennen das nicht...

    du kannst es leicht selbst einbauen, einfach ein kleines array von function pointern machen, dann den startup/exit-code so manipulieren, dass er, nachdem 'main' verlassen wurde, die liste durchgeht und alle funktionen darin aufruft.
    ach ja: wenn die main verlassen wird, geht die welt unter.
    🙂



  • ;fricky schrieb:

    wenn die main verlassen wird, geht die welt unter.
    🙂

    Achsoo, und ich dachte, wenn die welt verlassen wird, gibt's keine main() mehr.
    Bin eh grad am Abwägen, ob goto praktischer ist oder das Selbstschreiben eines C- Compilers und hab' dabei festgestellt, daß wir alle nur ein FIG- Port und somit völlig verdreht sind ... 😃
    Uiui, DAS war OT 🙄



  • Ich implementiere zu jedem Konstruktor auch immer einen Dekonstruktor. Ich hab diese bisher nur immer während des Programmablaufs aufgerufen, nie bei Prozessende. Wenn ihr der Meinung seid, dass das aber sinnvoll wäre, dann mache ich das ab jetzt in Zukunft immer.

    supertux schrieb:

    wo ist dann das Problem? Und wenn du dir das sparen willst, dann kannst du dir einen mini-garbage collector für deine Objekte mit man: atexit(3) basteln.

    Hey, die atexit-Funktion ist genial. Danke für den Tipp. 🙂

    ;fricky schrieb:

    du kannst es leicht selbst einbauen, einfach ein kleines array von function pointern machen, dann den startup/exit-code so manipulieren, dass er, nachdem 'main' verlassen wurde, die liste durchgeht und alle funktionen darin aufruft.

    Noch en besserer Tipp. Warum ne Lib benutzen wenn man es auch selber machen kann?

    Exceptions lass ich jetzt wahrscheinlich doch komplett wegfallen. Konsolenausgaben reichen für meine Programme bisher vollkommen aus.

    ;fricky schrieb:

    wie jetzt? einen webserver willste nicht in C aber in asm machen? das halte ich für keine gute idee. ok, wenn du spass daran hast, dann mach es, aber C finde ich gerade für sowas wie (embedded) webserver ideal. auch kannste C-code leichter auf andere targets portieren, was mit ASM nur geht, wenn der andere controller auf derselben CPU-familie basiert.

    Das liegt daran, dass das dar Mini-Webserver nicht besonders leistungsfähig ist - da halte ich selbst C für overpowered...
    Aber mal gucken wie groß der Aufwand im Endeffekt ist, vllt. lohnt sich es ja doch noch auf C umzusteigen.

    ;fricky schrieb:

    ach ja: wenn die main verlassen wird, geht die welt unter.

    Also, ich finde die Welt geht erst unter wenn die Lebensquelle(Stecker) nicht mehr ist...



  • Antoras schrieb:

    Noch en besserer Tipp. Warum ne Lib benutzen wenn man es auch selber machen kann?

    super, erfinde doch das Rad noch einmal, am besten lässt du dich das Rad 2.0 patentieren. 😕

    Viele Bibliotheken sind länger getestet und somit stabiler, was ein großer Vorteil bedeutet, vor allem, wenn man produktiv arbeitet. Außerdem haben viele auch Portierungen für andere Plattformen und wenn du ein Produkt für mehrere Plattformen haben willst, dann ist es blöd, alles selber machen zu müssen.

    Also, ich weiß nicht, ob du uns auf den Arm nehmen willst, oder echt ernst meinst, einen Webserver in ASM schreiben zu wollen, aber C als overpoweder zu halten 😕



  • supertux schrieb:

    super, erfinde doch das Rad noch einmal, am besten lässt du dich das Rad 2.0 patentieren. 😕

    Viele Bibliotheken sind länger getestet und somit stabiler, was ein großer Vorteil bedeutet, vor allem, wenn man produktiv arbeitet. Außerdem haben viele auch Portierungen für andere Plattformen und wenn du ein Produkt für mehrere Plattformen haben willst, dann ist es blöd, alles selber machen zu müssen.

    Ich hab halt einen Splean und möchte alles selber machen. Dass das aber nicht so ohne weiteres möglich und auch sinnvoll ist weiß ich aber auch. 😉

    supertux schrieb:

    Also, ich weiß nicht, ob du uns auf den Arm nehmen willst, oder echt ernst meinst, einen Webserver in ASM schreiben zu wollen, aber C als overpoweder zu halten 😕

    Ich glaub ich hab mich falsch ausgedrückt. Das wird ein Webserver für einen Mikrocontroller und nicht für einen PC. Hier steht das Programmieren der Hardwarefunktionen im Vordergrund. Deshalb meine Äußerung C sei hier overpowered. Zumindest eignet es sich imho nicht so gut zu lernen wie die Hardware arbeitet.



  • supertux schrieb:

    super, erfinde doch das Rad noch einmal

    Du hast natürlich recht. Aber ich kann die Freude gut nachvollziehen, daß man mit C auf einmal "on the bare metal" ist:

    Antoras schrieb:

    Noch en besserer Tipp. Warum ne Lib benutzen wenn man es auch selber machen kann?

    Letztlich sicher eine Design-Frage: willst du unabhängig sein: dann bau es selbst. Willst du auf der Arbeit anderer aufbauen: das hat viele Vorteile.

    pointercrash() hat ja darauf hingewiesen, daß es kleine Systeme gibt, die nicht den ganzen Standard umsetzen. Sich nur nichts einreden lassen: es ist dein Programm, und du bestimmst die Ziel-Platformen.

    Antoras schrieb:

    Das liegt daran, dass das dar Mini-Webserver nicht besonders leistungsfähig ist - da halte ich selbst C für overpowered...
    Aber mal gucken wie groß der Aufwand im Endeffekt ist, vllt. lohnt sich es ja doch noch auf C umzusteigen.

    Gute Gelegenheit, zu erforschen, wie gut die beiden zusammenspielen können. Ist ja auch bei Betriebssytemen üblich, so früh als möglich C zu verwenden. Da kann man sicher was lernen.



  • Antoras schrieb:

    Exceptions lass ich jetzt wahrscheinlich doch komplett wegfallen. Konsolenausgaben reichen für meine Programme bisher vollkommen aus.

    Meinst du zum Debuggen?



  • Antoras schrieb:

    Ich hab halt einen Spleen und möchte alles selber machen. Dass das aber nicht so ohne weiteres möglich und auch sinnvoll ist weiß ich aber auch. 🙂

    Zunächst einmal hängt alles nur davon ab, was du dir alles zutraust zu programmieren. 🙂

    Später hängt alles davon ab wie schnell du dabei bist. 😞

    Der Satz: mit dem Rad erfinden und so ist auch nur ein Dogma.



  • Antoras schrieb:

    Ich glaub ich hab mich falsch ausgedrückt. Das wird ein Webserver für einen Mikrocontroller und nicht für einen PC. Hier steht das Programmieren der Hardwarefunktionen im Vordergrund. Deshalb meine Äußerung C sei hier overpowered.

    ein webserver hat ja mit der hardware direkt nix am hut, der muss HTTP-anfragen beantworten und daten versenden. dazwischen hängt noch ein TCP-stack, der auch nicht direkt die hardware ansprechen muss. erst dann kommt ein treiber für's netzwerkinterface, der zwar mit der hardware redet, aber selbst solche treibersachen sind meistens zu 99% in C implementiert.

    auf welchem controller soll dein webserver denn laufen?
    vielleicht wird dich das interessieren: http://www.iosoft.co.uk/tcplean.php
    🙂


Anmelden zum Antworten