C++ und C, Unterschied



  • 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.



  • Wutz schrieb:

    Du willst diese Daten als VLA innerhalb der Funktion benutzen

    Wozu sollte ich Daten, die nicht als VLA vorliegen, als VLA behandeln wollen?



  • Schon wieder richtig erkannt, aber aufgrund deiner fehlenden Erfahrung falsch geschlussfolgert.

    Ähh, ja ich glaube da unterschätzt du mich ein wenig. Ich bin kein C Profi, aber auch kein Noob mehr.

    Deswegen übergibt man explizit nur Verweise, im C++ Jargon auch Referenz genannt.

    Ich spreche da lieber von Zeigern auch wenn man diese derefernziert. 😉

    Und ist ja klar. Ich möchte mir nicht den Wolf kopieren, weil ich ständig call-by-value mache. Aber in meinem Beispiel war es ein wenig anders. Ich kopierte nicht die Daten in das lokale Array, sondern ich führte eine Berechnung auf dieser lokalen Datenstruktur durch. VLA nutzte ich nicht, weil es der Compiler nicht kannte.

    Natürlich ist die Datenstruktur ein wenig gekünstelt, auch wenn dies bei mir schon in der Praxis vorkam. Die Datenstruktur war anfangs rank und schlank und wuchs weiter und weiter bis ich ein Redesign durchführte.

    In der Summe: Ich sehe nicht so den Vorteil von VLA.



  • Bitte ein Bit schrieb:

    VLA nutzte ich nicht, weil es der Compiler nicht kannte.

    int Test(int Size)
    {
      tStrasse List[Size];
       
      //return Test2();
      return 0;
    }
    

    Das ist dein Code und das ist VLA. Und ich nehme an, dass du in der Funktion Test auch irgendwas mit deiner Liste anfangen willst.



  • Bitte ein Bit schrieb:

    Ich hätte ein Antwort nach dem Motto "Dann erhöhen wird doch einfach den Stack Speicher." erwartet.

    Du verstehst nicht ganz. VLAs reduzieren die Stackspeichernutzung.

    int size = ... // maximal 1024, kann aber auch kleiner sein.
    char line[size]; // minimale Größe
    

    VLAs an Stellen nutzen, wo die Größe absolut unbekannt ist, ist nicht gut. Wenn performancemäßig nötig, mache ich dann ein if (i_can_has_vla)/else malloc.

    Im Gegenteil: Alle Arrays so zu wählen, dass die Größe sicher ausreicht, führt zu Stacküberläufen und Cachemisses.



  • Ich hätte gerne VLAs für Threading mit OpenMP. häufig brauche ich nur ein paar Byte pro Thread und müsste mir, weil die Anzahl der Threads dynamisch ist, teuer speicher vom Heap holen. Für microthreads echt unangenehm. Dann lieber einmal kurz etwas mehr Speicher vom Stack holen.



  • otze schrieb:

    Ich hätte gerne VLAs für Threading mit OpenMP. häufig brauche ich nur ein paar Byte pro Thread und müsste mir, weil die Anzahl der Threads dynamisch ist, teuer speicher vom Heap holen. Für microthreads echt unangenehm. Dann lieber einmal kurz etwas mehr Speicher vom Stack holen.

    Wenn du's wirklich brauchst: Praktisch jeder Compiler unterstützt sowas wie alloca()... 😉



  • Wenn performancemäßig nötig, mache ich dann ein if (i_can_has_vla)/else malloc.

    Und da wird es meines Erachtens wichtig, eine saubere Programm-Struktur zu haben, damit man sich kein Speicherloch einfängt.

    Ich hätte gerne VLAs für Threading mit OpenMP. häufig brauche ich nur ein paar Byte pro Thread und müsste mir, weil die Anzahl der Threads dynamisch ist, teuer speicher vom Heap holen. Für microthreads echt unangenehm. Dann lieber einmal kurz etwas mehr Speicher vom Stack holen.

    Für welche Dinge benötigt man solche Mikro-Optimierungen?

    Ist es da nicht besser an der Komplexitätsklasse rumzuschrauben?


  • Mod

    Bitte ein Bit schrieb:

    Ist es da nicht besser an der Komplexitätsklasse rumzuschrauben?

    Ich lege dir mal alle meine mikrooptimierten Programme vor, du erklärst mir dann, wie ich die Komplexitätsklasse hätte verbessern können?



  • Ich lege dir mal alle meine mikrooptimierten Programme vor, du erklärst mir dann, wie ich die Komplexitätsklasse hätte verbessern können?

    Was soll das? 😡

    Ja gerne. Ich würde mal gerne ein Programm sehen. Was für Programme sind das, für die sich solche Optimierungen lohnen? High-End Simulationen? Interrupt Funktionen?

    Hier wird von OpenMP und Threads gesprochen. Aber gleichzeitig auch von teueren malloc Aufrufen, Microthreads und Cachemisses. Und den Sinn dahinter verstehe ich nicht. Ich verstehe es nicht wie man OpenMP nutzen kann, und dann bei Optimierungsproblemen wie Microthreads und Cachemisses hängen bleibt.

    Annahme: Ich führe eine Berechnung mit N Threads durch. Durch einen Fehler sind N-1 Threads schnell fertig, wodurch aber der letzte Threads umso länger benötigt... Und da der Hauptthread auf das Ende aller Threads wartet, ist kein Zeitgewinn durch die Threads zu erwarten.

    Lohnen sich Microthreads denn überhaupt, da der Kontextwechsel einen nicht unerheblichen Beitrag zur Thread Laufzeit leistet?

    Wenn Cache Misses ein Problem sind, sollte ich mir überlegen einen Non-Paged Memory Pool zu allokieren oder gleich einen entsprechenden Treiber zu schreiben um direkten Zugriff auf die Hardware zu haben und um das Betriebssystem zu umgehen.

    Und was macht der Optimierer überhaupt? Nutzt dieser den kompletten Befehlsatz der CPU? Kämpfen Mikrooptimierungen nicht gegen den Optimierer? Oder sollen Mikrooptimierungen den mangelhaften Optimierer/Compiler ausgleichen?

    Ich habe es schon erlebt dass man effizient programieren wollte, man sich aber viele Nebenbedingungen einhandelte, das Design darunter Not litt und am Ende sogar langsamer war. Und darum bin ich vorsichtig in Sache Mikro-Optimierungen.


  • Mod

    Bitte ein Bit schrieb:

    Ich lege dir mal alle meine mikrooptimierten Programme vor, du erklärst mir dann, wie ich die Komplexitätsklasse hätte verbessern können?

    Was soll das? 😡

    Es soll dich darauf aufmerksam machen, dass die Anmerkung, mal eben so die Komplexitätsklasse zu verbessern, Unsinn ist, wenn es um ein Argument gegen Mikrooptimierung geht.

    Wenn du so weit bist, dass du optimierst, dann liegt die Auswahl des Algorithmus schon lange hinter dir und natürlich hat man den allerbesten Algorithmus gewählt, man ist ja nicht doof. Aber der soll natürlich auch noch möglichst schnell laufen. Daher Optimierung.



  • Für mich ist C++ im Gegensatz zu C eine Mehrparadigmensprache auf Systemebenen. Wenn es nicht anderes Sinn macht versuche ich mich auch in C oder auch C++. Spaß machen aber beide Sprachen nicht wirklich, es gibt einfach zu viel was einen von der eigentlichen Arbeit(Implementieren von Algorithmen, etc,) ablenkt.

    Am meisten Spaß macht mir derzeit Java mit Eclipse, da habe ich ganz wenig mit der Sprache selbst zu kämpfen und kann mich auf das Problemlösen konzentrieren.

    Aber das war ja auch nicht die Frage und fast jeder Entwickler programmiert eh mit unterschiedlichen Sprachen. Ich persönlich habe bis jetzt Kontakt gehabt mit: C, C++, PHP, Javascript, Python, Bash und Java.

    Hochoptimierte Software wurde noch nie verlangt und ich habe auch keinen Kollegen bis jetzt kennen gelernt, der so etwas abliefern musste. In meine Augen sind so etwas absolute Spezialfälle.



  • B4ndit schrieb:

    Für mich ist C++ im Gegensatz zu C eine Mehrparadigmensprache auf Systemebenen. Wenn es nicht anderes Sinn macht versuche ich mich auch in C oder auch C++. Spaß machen aber beide Sprachen nicht wirklich, es gibt einfach zu viel was einen von der eigentlichen Arbeit(Implementieren von Algorithmen, etc,) ablenkt.

    C++ hat mehr Algorithmen, als man in einem normalen Programm braucht. 🙄



  • Nathan schrieb:

    C++ hat mehr Algorithmen, als man in einem normalen Programm braucht.

    C++ hat sehr viele Algorithmen, die kein normales Programm braucht, aber es fehlen Algorithmen, die viele normale Programme brauchen würden.

    Trifft nicht nur auf Algorithmen, sondern auch auf Container und das IO-Gedöns zu.



  • Nathan schrieb:

    B4ndit schrieb:

    Für mich ist C++ im Gegensatz zu C eine Mehrparadigmensprache auf Systemebenen. Wenn es nicht anderes Sinn macht versuche ich mich auch in C oder auch C++. Spaß machen aber beide Sprachen nicht wirklich, es gibt einfach zu viel was einen von der eigentlichen Arbeit(Implementieren von Algorithmen, etc,) ablenkt.

    C++ hat mehr Algorithmen, als man in einem normalen Programm braucht. 🙄

    Die meisten C++-"Algorithmen" sind doch völlig triviale Schleifen. Deine Reaktion geht auch völlig an der Kritik von B4ndit vorbei, nämlich dass C++ die Aufmerksamkeit vom Wesentlichen ablenkt. Und damit hat er recht.



  • Hört hört...

    Dann mach doch Visual Basic und werd glücklich.



  • @Bitte ein Bit In meinem Fall ist es der SMO-Algorithmus zur Maximierung von quadratischen Problemen mit Box-Constraints. Da man in dem Algorithmus fundamental Speicherbandbreitenlimitiert ist, kann man dort durch Parallelisierung mehr als linearen Speedup erreichen(n cores => >n fach schneller). Die Schleife die ich da optimiert habe, war nicht wirklich teuer, durch Parallelisierung hat man da alleine nicht viel gewinnen können. Das Einzige was man gewann war, das durch das konsequente Teilen des Problems auf n Kerne der L1+L2 Cache eines Kerns in der Schleife nicht geflusht wurde. Das unnötige malloc mit dem cache miss tat dann schon weh. Mit VLA wäre das ein no-brainer gewesen, jetzt drufte ich mir überlegen, wie ich das pre-allokieren kann. Am Ende wurde es ein normales Array auf dem Stack mit recht großzügiger Dimensionierrung. Naja, muss ich mit leben.

    OpenMP selbst kostet fast nichts, das ist wirklich fix implementiert. Es ist ja auch dafür gedacht, relativ einfache Schleifen zu parallelisieren. Keine Panik, wir Benchmarken schon unsere Programme 😉


Anmelden zum Antworten