Zwei kleine Selbsttests über euer C-Wissen



  • Ich dank euch beiden Mal.

    Hab zwar gleich die Onlineversion benutzt, wobei mein PDF Viewer wohl auch nicht gewollt hätte.

    Einiges vieles Neues kann man da sicherlich lesen, nur zu empfehlen. Vor allem der 2. Link.



  • Deep-C: Fuer mich nichts neues. C++ kommt etwas kurz. Da gibt es noch einige Fallstricke gerade im Zusammenhang mit virtuellen Methoden. Aber Vollstaendigkeit ist auch schwer zu erreichen. Sonst finde ich es gut, dass es sich auch andere ansehen.
    Will It Optimize: Erstes Beispiel mit Rekursion: Das ist eine Kindergartenaufgabe fuer den Kompiler, ein etwas komplexeres Beispiel waere angebracht.



  • Der Irrglaube, die Größe einer struct/class wachse durch hinzufügen durch non-virtual Funktionen ist natürlich nett 😃



  • Leider kompiliert das erste beispiel nicht mit VS2010.
    int main()
    {
    int a = 42;
    printf("%d/n",a);
    }

    1>ClCompile:
    1> basic.cpp
    1>c:\users\shiba\documents\visual studio 2010\projects\kata\basic\basic\basic.cpp(4): error C3861: "printf": Bezeichner wurde nicht gefunden.
    1>
    1>Fehler beim Erstellen

    Heißt das nun, das MS C nicht standardkonform oder das der Test blödsinnig ist?



  • Shiba schrieb:

    Heißt das nun, das MS C nicht standardkonform oder das der Test blödsinnig ist?

    Edit: Blubb. Ist ja eine .cpp Datei. oO



  • Es bedeutet, dass MSVC Quellcodedateien, die in .cpp enden, als C++-Code zu übersetzen versucht. Dort gibt es keine implizite Funktionsdeklaration wie in C, und deshalb lehnt der Compiler den Code in Übereinstimmung mit dem C++-Standard ab.

    Benenn die Datei in basic.c um, dann wird er sie auch fressen.



  • Shiba schrieb:

    1> basic.cpp

    Wenn du es als C++ kompilieren willst, dann funktioniert es natürlich nicht. Ist aber auf den Folien auch erklärt.



  • Danke Seldon.



  • Der MSVC besitzt auch einen Schalter, mit dem unabhängig von der Dateiendung der Compiler ausgewählt wird: /TP: C++, /TC: C (einzustellen bei MSVS 2008 unter project->properties->advanced->compile as),



  • Nachdem ihr mir so auf die Sprünge geholfen habt, noch eine Frage.
    In den Slides 125 bis 137 geht es um Calling conventions und activation frames
    anhand folgenden Beispiels

    #include <stdio.h>
    
    void foo(void)
    {
     int a;
     printf("%d\n",a);
    }
    
    void bar(void)
    {
      int a = 42;
    }
    
    int main (void)
    {
      bar();
      foo();
    }
    

    Nun wird behauptet, das kompiliert mit c foo.c && ./a.out.
    42 herauskommt.
    Kompilier ich das mit VC, dann erhalte ich den Müll aus dem nicht initialisierten a von foo().
    Ich bin auch der Meinung, das eine Funktion nicht durch "übersprechen" auf dem Stack einen Variablenwert bekommt.
    Was ist mit diesem Beispiel gemeint?



  • Wird der Funktionsaufruf von bar bei dir wegoptimiert? Sollte aber in den weiteren Folien erwaehnt sein.


  • Mod

    Die Funktionen und ihre Variablen werden auf den Stack gelegt. Lass uns mal ein etwas komplexeres Beispiel machen:

    #include <stdio.h>
    
    void foo(void)
    {
     int a;
     printf("%d\n",a);
    }
    
    void bar(void)
    {
      int a = 42;
    }
    
    int main (void)
    {
      int damit_nicht_alles_leer_ist = 5;
      bar();
      foo();
    }
    

    Der Stack nach Ausführen der Zeile 16 sieht so aus

    Müll
       Müll
       Mull
    -> 5
    

    Wobei -> der Stackpointer sein soll.
    Nun springen wir in bar:

    Müll
       Müll
    -> Müll
       5
    

    Zeile 11 wird ausgeführt:

    Müll
       Müll
    -> 42
       5
    

    bar ist zuende:

    Müll
       Müll
       42
    -> 5
    

    Und es wird foo aufgerufen:

    Müll
       Müll
    -> 42
       5
    

    Und so kommt es, dass a in foo den Wert 42 haben kann, wenn vorher nichts optimiert wurde. Und die Maschine überhaupt etwas wie einen Stack hat. Und allerhand andere Voraussetzungen gelten, die ich nicht alle aufführen will, es hat gute Gründe, warum das Verhalten undefiniert ist. Es kann nur unter gewissen, an normalen Heimcomputern geltenden, Voraussetzungen so sein.



  • @ knivil. Nein bar wird nicht wegoptimiert.

    @seppj
    Danke für die Antwort.
    Aber es will mir nicht in den Kopf! Wenns gleich merkwürdig klingt, ich hab keine Ahnung von diesem Thema.
    Erstens ich finde bei meiner IDE im Debug nur einen Call Stack, der mir eine Funktionsaufruflist gibt.
    Wie kann ich mir diesen Stack anschauen, den Du beschreibst?

    Noch besser hast Du vielleicht eine Quelle, wo ich mich einlesen kann?


  • Mod

    Call stack ist schon das passende Stichwort. Meine Darstellung war natürlich stark vereinfacht:
    http://en.wikipedia.org/wiki/Call_stack



  • Ich habs jetzt mal mit ggc kompiliert und das prophezeite Ergebnis nicht hinbekommen. Habe ich eigentlich auch nicht erwartet.
    Aber den Link werde ich studieren und meinen Horizont erweitern.
    Danke.



  • Shiba schrieb:

    @ knivil. Nein bar wird nicht wegoptimiert.

    Wenn ich mit Visual Studio 2005 im Release Modus Compiliere und mir den Assembler-Output ansehe, dann wird bar bzw. int a = 42 wegoptimiert. Mit gcc kann ich gerade nicht testen.


  • Mod

    Shiba schrieb:

    Ich habs jetzt mal mit ggc kompiliert und das prophezeite Ergebnis nicht hinbekommen. Habe ich eigentlich auch nicht erwartet.
    Aber den Link werde ich studieren und meinen Horizont erweitern.
    Danke.

    Also ich kann es mit gcc 4.4 reproduzieren. Irgendwie habe ich stark den Verdacht, dass du irgendwo unabsichtlich optimierst. So abgefahren undefiniert ist der Effekt nämlich nicht, sondern ziemlich genau was man bei unoptimiertem Code auf herkömmlichen Compilern und Maschinen erwarten würde.



  • Ist nicht ausgeschlossen, das ich da Fehler mache.
    Werde mir die Optimierung und die Kompilation mit gcc nochmal vornehmen.
    Vielen Dank-



  • Ich finde Folie 370 ist immer noch crap.

    "Wenn man schon irgendwo new array benutzt" sollte man ein try catch drum herum bauen falls nicht genügend speicher zur Verfügung steht.

    Außerdem sollte man für solche Zwecke eher std::size_t übergeben und nicht int.

    Desweiteren sollte man prüfen ob std::size_t nicht 0 ist.

    Wenn irgendwas beim new falsch läuft sollte man den Zeiger auf NULL setzen.

    Im Destruktor muss eine if(v) { delete v [] };

    Da ist dem Autor wahrscheinlich die Puste ausgegangen? Wohl eher ein C Programmierer???



  • Folie 382 hat auch überhaupt nichts mit C++ zu tun. Das macht man einfach so nicht.

    Außerdem wird nirgendwo return EXIT_SUCCESS; angegeben obwohl es eigentlich zum guten Ton gehört.


Anmelden zum Antworten