C++ und C, Unterschied



  • Bitte ein Bit schrieb:

    flexible array members

    Welch fehleranfälliges Konstrukt...

    Wird aber anscheinend gebraucht. Früher hat man dazu ein Array der Größe 0 ans Ende der Struktur gepackt.

    VLA hat einen massiven Nachteil:

    Es liegt auf dem Stack.

    Glückwunsch zu deinem trockenen Humor.



  • Old Skool Progger schrieb:

    Player894 schrieb:

    Hallo,

    ich habe jetzt unterschiedlichstes über C und C++ über Foren, Kollegen und Freunde erfahren.
    Kann mir das bitte jemand einmal genau aufdröseln, was man jetzt wie machen kann, wie die Sprachen zusammenhängen etc.?

    C++ ist C mit Klassen.

    Viel mehr ist da nicht dahinter.

    😮
    Und Metaprogrammierung mit Templates etc. lässt du einfach mal weg? 👎

    Bitte ein Bit schrieb:

    VLA hat einen massiven Nachteil:

    Es liegt auf dem Stack. Und da C Datenstruktuen nicht dazu neigen rank und schlank zu sein, frisst dies schnell den Stack weg, s.d. das System je nach Lust und Laune sich verabschiedet.

    Das ist jetzt nicht dein ernst, oder?



  • SeppJ schrieb:

    Zwei (übertriebene) Beispielprogramme:
    http://www.99-bottles-of-beer.net/language-c-116.html
    http://www.99-bottles-of-beer.net/language-c++-111.html

    SeppJ, ich bin enttäuscht: Da gibt es so schöne C++ Beispiele, wie das oder das. :p

    @Old Skool Progger: Herzlichen Glückwunsch, du hast C++ verstanden.



  • Nathan schrieb:

    @Old Skool Progger: Herzlichen Glückwunsch, du hast C++ verstanden.

    Klar habe ich das, nur wollte ich meinen Spaß haben und ihr habt angebissen. 😃 :p



  • K&R schrieb:

    Das ist jetzt nicht dein ernst, oder?

    Bedingt. Es ist doch so eine typische Sache das man unter C alles selbst machen muss. Und selbst bei einigen schlechten C Compilern erlebt dass man die Optimierung auch in die Hand nehmen muss, da der Code fast eins zu eins in Assembly umsetzt wird.

    Und da habe ich den gleichen Schnellschuss gezogen...

    Wer erwartet denn hinter VLA eine ausgeklügelte Speicherverwaltung? Ich nicht. 😞



  • Old Skool Progger schrieb:

    Nathan schrieb:

    @Old Skool Progger: Herzlichen Glückwunsch, du hast C++ verstanden.

    Klar habe ich das, nur wollte ich meinen Spaß haben und ihr habt angebissen. 😃 :p

    Verdammt, ich hab mir noch sowas gedacht... 😡 😉


  • Mod

    Bitte ein Bit schrieb:

    K&R schrieb:

    Das ist jetzt nicht dein ernst, oder?

    Bedingt. Es ist doch so eine typische Sache das man unter C alles selbst machen muss. Und selbst bei einigen schlechten C Compilern erlebt dass man die Optimierung auch in die Hand nehmen muss, da der Code fast eins zu eins in Assembly umsetzt wird.

    Und da habe ich den gleichen Schnellschuss gezogen...

    Wer erwartet denn hinter VLA eine ausgeklügelte Speicherverwaltung? Ich nicht. 😞

    Ich glaube, du verstehst nicht: Der Vorteil von VLAs ist, dass sie auf dem Stack liegen. Das man nicht ungeprüft riesige Arrays auf den Stack legen sollte ist Aufgabe des Programmierers. Genau wie dieser auch alles andere vermeiden muss, was man so falsch machen könnte. Richtiges Programmieren eben.



  • SeppJ schrieb:

    (VLAs? Wirklich? Das ist dein Beispiel? Die sind in C11 sogar wieder zu einem optionalen Feature herabgestuft worden, weil sie doof sind.),

    Ich glaube nicht an diesen Erkenntnisgewinn in der WG14, ich tippe auf einen unüberlegten Schnellschuss in dieser Truppe aufgrund Einflüsterungen Einzelner, genau wie damals, als sie sich in C99 das Zeugs überhaupt ausgedacht haben.
    Curacao aus Austragungsort solcher Diskussionen+Beschlussfassungen auszuwählen legt per se schon eine gewisse Naivität für Ergebnisse solcher "Konferenzen" nahe.
    http://www.open-std.org/jtc1/sc22/wg14/www/documents



  • SeppJ schrieb:

    Das man nicht ungeprüft riesige Arrays auf den Stack legen sollte ist Aufgabe des Programmierers.

    Und wie prüfe ich, ob genug Platz auf dem Stack ist?



  • Bitte ein Bit schrieb:

    VLA hat einen massiven Nachteil:
    Es liegt auf dem Stack.

    SeppJ schrieb:

    Der Vorteil von VLAs ist, dass sie auf dem Stack liegen.

    VLA sind ein einziger Nachteil.
    Der Standard kennt überhaupt keinen Stack, demzufolge schreibt er sowas wie auch alle anderen gern in diesem Zusammenhang genannten Weisheiten bzgl. Implementierungen nicht vor.
    Ein Compilerhersteller kann VLA auch im Heap (wird auch vom Standard nicht gekannt) anlegen und wäre immer noch standardkonform.



  • Des einen Stack ist des anderen automatic storage duration.


  • Mod

    Tyrdal schrieb:

    SeppJ schrieb:

    Das man nicht ungeprüft riesige Arrays auf den Stack legen sollte ist Aufgabe des Programmierers.

    Und wie prüfe ich, ob genug Platz auf dem Stack ist?

    Auf die gleiche Art und Weise, wie du weißt, ob deine normalen Variablen auf den Stack passen: Du legst einfach keine riesengroßen Objekte auf den Stack und hoffst, das mit dieser Faustregel schon alles passen wird! Oder prüfst du vor jedem Funktionsaufruf, ob dieser nicht den Stack überlaufen lassen könnte?

    Besser ist natürlich zu überlegen, ob du ein überhaupt ein VLA möchtest. Schließlich läuft obige Prüfung darauf hinaus, ob das Array größer oder kleiner wäre als das größte Array mit statischer Größe, das du noch guten Gewissens auf den Stack legen würdest. Warum dann nicht ein statisches Array dieser Größe nehmen?



  • #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct
    {
      char Name[256];
      char Vorname[256];
      int Alter;
    } tPerson;
    
    typedef struct
    {
      tPerson Personen[32];
      int Anzahl;
    } tHaus;
    
    typedef struct
    {
      tHaus Haus[50];
      int Anzahl;
    } tStrasse;
    
    int Test2(void)
    {
      tStrasse S2;
    
      S2.Anzahl = 0;
      return 0;
    }
    
    int Test(int Size)
    {
      tStrasse List[Size];
    
      //return Test2();
      return 0;
    }
    
    int main(int argc, char** argv)
    {
      Test(1);
      return 0;
    }
    

    Mit Test(1) funktioniert es noch. Bei Test(2) kommt schon die Stack Overflow Fehlermeldung. Und dies ist kein untypisches Array!

    Der Fehler ist sporadisch, da er abhängig von der aktuellen Stack Belegung ist und der Größe des Funktionsparameters Size!

    Wie soll man solch ein Problem lösen?

    Ein Compilerhersteller kann VLA auch im Heap (wird auch vom Standard nicht gekannt) anlegen und wäre immer noch standardkonform.

    Wer macht das schon? Das Ganze endet doch dann in nicht portablen Code.


  • Mod

    Bitte ein Bit schrieb:

    Und dies ist kein untypisches Array!

    Ähh, doch? Selbst ein Einzelobjekt mit einer sizeof wie tStrasse würdest du niemals in den automatischen Speicher stecken, geschweige denn ein Array davon anlegen.

    P.S.: Für alle, die nicht rechnen möchten: sizeof(tStrasse) == 825804, falls sizeof(int)==4.



  • Bitte ein Bit schrieb:

    C++ ist für meinen Geschmack eine Sprache auf einem anderen Abstraktionsniveau. In C ist das Abstraktionsniveau niedrig.

    Das war auch nicht anders beabsichtigt.
    C ist von Praktikern für die Praxis entwickelt worden und dabei schon mal sehr portabel ausgelegt worden.
    Im Gegensatz zu Theoretikern wie Stroustrup haben K&R ihr Ergebnis auch selbst eingesetzt, mehr noch, sie haben schon bei der Entwicklung der Sprache die konkreten Einsatzfälle im Auge gehabt, und eben nicht irgendwelche Fallstricke, über die 40 Jahre später immer noch viele Leute stolpern (könnten).
    Stroustrup war ja noch nicht mal in der Lage, eine konkrete Referenzimplementierung eines C++ Compilers anzubieten, d.h. natürlich auch, dass er die Anforderungen an seine Sprache von der Praxis aus gesehen überhaupt nicht kennen geschweige denn testen konnte.

    Bitte ein Bit schrieb:

    In C++ kümmert man sich darum meist wenig, denn mit ein wenig Sorgfalt lassen sich in C++ viele typische C Fehler vermeiden.

    Genau richtig. Deshalb sollte ein C++ler auch niemals mit ureigenen C-Mitteln rumhantieren, davon hat er eh keine Ahnung; muss er ja auch nicht haben wenn er die C++ Intention verstanden hat, die eben gerade vom Lowlevel abhebt;
    denn trotz des geringen Sprachumfanges stecken in C wie man auch sehr oft hier im Forum sieht, viele Hürden und Aberglauben.



  • Bitte ein Bit schrieb:

    Der Fehler ist sporadisch, da er abhängig von der aktuellen Stack Belegung ist

    Richtig erkannt; und nur Anfänger/Fachbuchautoren/Hochschuldozenten verwenden nicht zwingend notwendige Abhängigkeiten.



  • Bitte ein Bit schrieb:

    Wie soll man solch ein Problem lösen?

    Du hast auch nicht sehr viel Ahnung.
    Für sowas gibt es alloca, zumindest bei BSD und gcc vorhanden, wenn auch kein ISO Standard. Das hätten die in C11 mal aufnehmen sollen und nicht diesen vielfach praxisirrelevanten Müll.



  • Selbst ein Einzelobjekt mit einer sizeof wie tStrasse würdest du niemals in den automatischen Speicher stecken, geschweige denn ein Array davon anlegen.

    Ja vielleicht.

    Aber die Gefahr ist doch dass man sowas unbeabsichtigt tut. Da ändert man hier eine Größe, mal da und blub kommt es zu einem Stack Overflow. In meinem Beispiel führt jedes weitere Zeichen in tPerson.Name dazu das 32*50 Bytes mehr benötigt werden.

    Nicht gut...

    Wollte man aber sicher sein, dürfte man bei VLA keine Structs nehmen.

    Du hast auch nicht sehr viel Ahnung.

    Liegt wohl daran dass das eine Fangfrage war. Ich hätte ein Antwort nach dem Motto "Dann erhöhen wird doch einfach den Stack Speicher." erwartet.

    Für sowas gibt es alloca, zumindest bei BSD und gcc vorhanden, wenn auch kein ISO Standard.

    In der Unix Welt kenne ich mich nicht aus. Würde aber natürlich für VLA die Sache ein wenig besser machen. Auch wenn das Kernproblem bleiben würde.


  • Mod

    Bitte ein Bit schrieb:

    Selbst ein Einzelobjekt mit einer sizeof wie tStrasse würdest du niemals in den automatischen Speicher stecken, geschweige denn ein Array davon anlegen.

    Ja vielleicht.

    Aber die Gefahr ist doch dass man sowas unbeabsichtigt tut. Da ändert man hier eine Größe, mal da und blub kommt es zu einem Stack Overflow. In meinem Beispiel führt jedes weitere Zeichen in tPerson.Name dazu das 32*50 Bytes mehr benötigt werden.

    Nicht gut...

    Das gilt für jeden Datentyp und unabhängig von VLAs.

    Das ist hier auch ein Designproblem deines Datentyps TStrasse. Das ist eine typische Art von Datensatz, die man überhaupt nicht in ein struct auf Anwendungsebene stopft, sondern wo man bloß ein Handle anbietet. Und wenn man schon so weit ist, dass man ohnehin ein Handle anbietet, dann kann man es auch gleich dynamisch machen, anstatt sinnlos 800kB zu reservieren, von denen man 799 wahrscheinlich sowieso nicht braucht, dafür aber Probleme hat, wenn der Name mal mehr als 255 Zeichen hat.

    Frei nach Wutz: Problem an dem Beispiel ist schlechte Benutzung von C, nicht C. Und (hier) auch nicht das spezielle Sprachfeature VLA.

    Wollte man aber sicher sein, dürfte man bei VLA keine Structs nehmen.

    Wieso? Wenn ich sage, dass du dein VLA dagegen absichern musst, dass es nicht größer werden kann als gut wäre, dann beinhaltet das natürlich auch, die Größe der Elemente zu beachten, nicht bloß die Anzahl.



  • Bitte ein Bit schrieb:

    In meinem Beispiel führt jedes weitere Zeichen in tPerson.Name dazu das 32*50 Bytes mehr benötigt werden.

    Nicht gut...

    Schon wieder richtig erkannt, aber aufgrund deiner fehlenden Erfahrung falsch geschlussfolgert.
    Wie SeppJ schon andeutete:

    Es ist designmäßig naiv (inperformant,fehleranfällig,...) eigentliche Nutzdaten im Stack zu halten. Wenn dann sind allenfalls "Hilfsdaten" im Stack denkbar, die dann auch wirklich nur innerhalb der Funktion Verwendung finden.
    Es ist deswegen Unsinn, weil du bei Übergabe der Daten an/Übernahme der Daten von der Funktion sie jedesmal kopieren müsstest.
    Deswegen übergibt man explizit nur Verweise, im C++ Jargon auch Referenz genannt.
    Und genau dieses (einfache) Fallmuster hat Ritchie schon vor 40 Jahren erkannt und diese Quasireferenz für Arrays als Funktionsparameter mit in die Sprache eingebaut, indem bei Übergabe bei Arrays immer nur der Verweis übergeben wird und nicht etwa der gesamte Arrayinhalt (durch call by value auf den Stack kopiert wird).

    Du willst diese Daten als VLA innerhalb der Funktion benutzen, d.h. du musst sie erstmal da rein kopieren, sie verarbeiten und anschließen wieder zurückkopieren:

    struct Bla {....};
    struct Bla meineDaten[1000000000];
    bla(meineDaten,1000000000);
    
    void bla(struct Bla *ptr, int x)
    {
      int i;
      struct Bla d[x];
      memcpy(d,ptr,sizeof d);
      ...
      hier irgendwas mit d anfangen
      for(i=0;i<x;++i)
        d[i] = ...
      ...
      memcpy(ptr,d,sizeof d);
    }
    

    Ich hoffe du erkennst die Schizophrenie des VLA-"Designs" für Nutzdaten, dass du ohne VLA viel schneller und sicherer arbeiten kannst:

    void bla(struct Bla *ptr, int x)
    {
      int i;
      ...
      hier irgendwas DIREKT mit ptr anfangen
      for(i=0;i<x;++i)
        ptr[i] = ...
      ...
    }
    

    Einzig zu beachten für Arrays hierbei ist, dass du die Längeninformation des Arrays, wenn sie dynamisch ist und zur Compilezeit nicht bekannt ist, separat übergeben musst.


Anmelden zum Antworten