Struct Rückgabewert



  • Hallo Sepp,

    ich habe den Code auch aus dem Original zusammenkopiert.

    Anbei der Code, wie er in meinem Programm Schmierblatt.c steht - komplett:

    #include <stdio.h>
    #include <math.h>
    
    typedef struct{
        double vx; //x value
        double vy; //y value
    } TVector;
    
    typedef struct{
        double x; //x value
        double y; //y value
    } TPoint;
    
    double Vektorlaenge(TVector* V){return sqrt(V->vx*V->vx + V->vy*V->vy);}
    
    TVector GetVector(TPoint* P2, TPoint* P1){
    TVector V;
    V.vx = P2->x - P1->x;
    V.vy = P2->y - P1->y;
    return V;
    }
    
    int main(){
    TPoint P1, P2;
    TVector V;
    
    P1.x = .0;
    P1.y = .0;
    
    P2.x=1.;
    P2.y=1.;
    
    V = GetVector(&P2, &P1);
    printf("Vektorlaenge: %2.4f\n", Vektorlaenge(&V));
    
    getchar();
    return 0;
    }
    

    Ich benutze den TCC 64 bit Compiler.

    Resultat:
    Vektorlaenge: 0.0000

    Programmabsturz



  • Selbst der Code geht: http://ideone.com/TFg0IU
    Kompletten Rebuild machen und dann schauen. Optimierungen u.ä. deaktivieren.



  • Hab neben dem TCC Compiler auch noch den LCC Compiler installiert - gleiches Resultat.

    Optimierung ist für meinen Code sehr wichtig. Ich nutze diese "niedrigen" Compiler, da ich ohne großes Overhang arbeiten will - Performance ist sehr wichtig. Diese Funktion wird im Hauptprogramm später mehrere Millionen mal ausgeführt - und nicht nur diese.

    Mit welchem Compiler arbeitet ihr?



  • Was hat

    CJens schrieb:

    Optimierung ist für meinen Code sehr wichtig. Ich nutze diese "niedrigen" Compiler, da ich ohne großes Overhang arbeiten will -

    mit

    CJens schrieb:

    - Performance ist sehr wichtig. Diese Funktion wird im Hauptprogramm später mehrere Millionen mal ausgeführt - und nicht nur diese.

    zu tun?


  • Mod

    CJens schrieb:

    Optimierung ist für meinen Code sehr wichtig. Ich nutze diese "niedrigen" Compiler, da ich ohne großes Overhang arbeiten will - Performance ist sehr wichtig. Diese Funktion wird im Hauptprogramm später mehrere Millionen mal ausgeführt - und nicht nur diese.

    da hast du so ziemlich das komplette Gegenteil erreicht von dem, was du möchtest. Deine vielen Indirektionen und die einfachen Compiler führen zu schlecht optimiertem, umständlichen Code.

    Zum Problem: Das gezeigte Programm kann keine Probleme machen, mit egal welchem Compiler. Du machst irgendetwas anderes komisches. Nutz mal einen Debugger, um dein Problem genauer zu bestimmen.

    P.S.: Sehr oft kann man übrigens das teure Ziehen einer Wurzel vermeiden, indem man etwas genauer nachdenkt.



  • Weil ich es gerade gesehen habe:

    CJens schrieb:

    printf("Vektorlaenge: %2.4f\n", Vektorlaenge(&V));
    

    Es geht um die Angaben beim Formatspecifier.
    Die Zahl vor dem . sind nicht die Vorkommastelllen sondern gibt die Breite des gesamten Feldes an.
    Bei 4 Nachkommastellen, einer Vorkommastelle und Dezimalpunkt sind das mindestens 6.



  • Das ist richtig beobachtet, darf aber keinesfalls zu einem Fehler führen, da field width die minimal auszugebende Breite angibt.
    Abgeschnitten darf durch solche 'zu kleine' Gesamtbreite niemals irgendwas.



  • In der Funktion GetVektor wird die Variable VT vom Typ TVektor lokal deklariert und dann als Rückgabewert benutzt. Ist es nicht so, dass eine lokale Variable nach dem Verlassen der Funktion ihren Wert verliert?



  • Der Inhalt der lokalen Struktur wird bei diesem Funktionsaufruf in die Struktur des aufrufenden Kontextes kopiert, dabei ist es egal, dass die lokale Quelle ANSCHLIEßEND ihre Gültigkeit verliert.
    Das hängt damit zusammen, dass in C alles per call by value abläuft, d.h. die Objektwerte/inhalte werden kopiert; das gilt nicht nur für die Argumente einer Funktion sondern auch für die Rückgabe(werte).



  • Hi!

    http://en.wikipedia.org/wiki/Struct_%28C_programming_language%29

    Ich habe es gerade bei mir versucht, das Programm läuft ohne Probleme. Allerdings wundert es mich ein bisschen.
    Guck mal nach ob dein Compiler evtl. ein Problem damit hat, dass du deine Struktur falsch definiert hast.

    typedef struct name { komponente_1, ..., komponente_n }
              variable_1, ..., variable_m;
    

    So sollte es normaler Weise aussehen.
    Seid Ihr euch sicher dass es Standardmäßig mit jedem Compiler funktioniert den Bezeichner ("name") hinter den Strukturrumpf zu schreiben? 😕

    Lg



  • ...



  • typedef struct name { komponente_1, ..., komponente_n }
              variable_1, ..., variable_m;
    

    So sollte es normaler Weise aussehen.

    Sollte es nicht.
    Hier sind variable_1, ..., variable_m neue Typen und keine Variablen.

    Ohne typedef davor wäre es richtig:

    struct name { komponente_1, ..., komponente_n }
              variable_1, ..., variable_m;
    


  • Wutz schrieb:

    typedef struct name { komponente_1, ..., komponente_n }
              variable_1, ..., variable_m;
    

    So sollte es normaler Weise aussehen.

    Sollte es nicht.
    Hier sind variable_1, ..., variable_m neue Typen und keine Variablen.

    Und genau deshalb macht man es so nicht.

    Üblich wäre:

    typedef struct name { komponente_1, ..., komponente_n } name;
    name variable_1, ..., variable_m;
    


  • ...



  • SeppJ schrieb:

    da hast du so ziemlich das komplette Gegenteil erreicht von dem, was du möchtest. Deine vielen Indirektionen und die einfachen Compiler führen zu schlecht optimiertem, umständlichen Code.

    Zum Problem: Das gezeigte Programm kann keine Probleme machen, mit egal welchem Compiler. Du machst irgendetwas anderes komisches. Nutz mal einen Debugger, um dein Problem genauer zu bestimmen.

    P.S.: Sehr oft kann man übrigens das teure Ziehen einer Wurzel vermeiden, indem man etwas genauer nachdenkt.

    Erstmal danke, dass ihr so fleißig über mein Problem nachdenkt.
    Meine Erfahrung hat gezeigt, dass mein Programm mit dem TCC kompiliert sehr schnell ist - schneller als mit VC++2013 inkl. Optimierer. Einziges Manko: OpenMPI wird nicht unterstützt - aber das kommt eh erst später.

    Mit dem Optimierer kann es nicht zusammen hängen. Ich kompiliere mein Programm schön auf die altmodische Art und Weise:

    tcc.exe Pfad\Datei.c -o Pfad\Datei.exe

    Das ganze führe ich im NodePad++ mit NPPEXEC aus.

    Mit der Definition der Structs hatte ich nie Probleme. Die Datei Structs.h, in welcher ich alle Structs definiere, ist schon uralt und hat in allem Programmen stets funktioniert.

    P.s.: Ist pow(float, .5) schneller als das Ziehen einer Wurzel? Ansonsten weiß ich nicht, wie ich da die Länge ermitteln soll. Die Koordinaten können nämlich durchaus negativ werden.

    Ich werde das Ganze später mal in VC++ versuchen und Euch bescheid geben.



  • ...hab jetzt ein Projekt in VC++ erstellt, die *.c Datei wie sie ist eingefügt und mit dem Debugger ausgeführt.

    Ergebnis wie es sein soll: 1.4142

    Mist...
    Ich wollte auf dieses "mächtige" Tool mit den vielen Optionen, die ich als Maschinenbauer nicht verstehe, verzichten.

    Aber ich wäre trotzdem daran interessiert, wie ich das Wurzelziehen vermeiden kann. Hab etwas in Foren gestöbert und dort wurde geschrieben, dass sqrt schneller ist als pow(float, .5)


  • Mod

    CJens schrieb:

    Aber ich wäre trotzdem daran interessiert, wie ich das Wurzelziehen vermeiden kann. Hab etwas in Foren gestöbert und dort wurde geschrieben, dass sqrt schneller ist als pow(float, .5)

    IDas spezialisierte sqrt sollte natürlich schneller sein als das allgemeinere pow. Ich sagte jedoch, du sollst das Wurzelziehen vermeiden, nicht durch eine andere Operation ersetzen. Die Frage ist nicht, wie du die Länge effizient bestimmen kannst (da ist sqrt schon ok), sondern ob du überhaupt die Länge bestimmen musst. Das kann man aber nur beantworten, wenn man weiß, wozu du meinst, die Länge zu benötigen. Um konkret zu werden: Reicht nicht eventuell das Quadrat der Länge für dein Vorhaben?

    Mit der Definition der Structs hatte ich nie Probleme. Die Datei Structs.h, in welcher ich alle Structs definiere, ist schon uralt und hat in allem Programmen stets funktioniert.

    Dein Programm ist 100% korrekt. Lass dich nicht von One-Man-Army verwirren.

    Es liegt sehr wahrscheinlich auch nicht an tcc. Erstens kann ein Compiler nicht so falsch sein, dass er dieses triviale Programm falsch erzeugt. Zweitens habe ich es, um sicher zu sein, nochmal selber getestet. Erfolgreich. (tcc version 0.9.25 unter Linux)

    Das ganze führe ich im NodePad++ mit NPPEXEC aus.

    Ist zwar weit her geholt, aber hast du mal versucht, dies zu variieren und das entstandene Programm direkt auszuführen?

    ...hab jetzt ein Projekt in VC++ erstellt, die *.c Datei wie sie ist eingefügt und mit dem Debugger ausgeführt.

    Ich weiß zwar nicht wie (da ich kein VS benutze), aber es ist bestimmt auch möglich, die mit tcc erzeugte Executable mit dem VC-Debugger auszuführen. Der tcc kann auf jeden Fall auch Debugsymbole in die Exe einfügen.

    Es gibt natürlich auch noch die manuelle Methode, mit selbstgeschriebenen Debugausgaben:

    #include <stdio.h>
    #include <math.h>
    
    typedef struct{
      double vx; //x value
      double vy; //y value
    } TVector;
    
    typedef struct{
      double x; //x value
      double y; //y value
    } TPoint;
    
    double Vektorlaenge(TVector* V)
    {
      double l2;
      double l;
      fprintf(stderr, "Vektorlaenge: V->vx: %f V->vy: %f\n", V->vx, V->vy);
      l2 = V->vx*V->vx + V->vy*V->vy;
      fprintf(stderr, "Vektorlaenge: l2: %f\n", l2);
      l = sqrt(l2);
      fprintf(stderr, "Vektorlaenge: l: %f\n", l);
      return l;
    }
    
    TVector GetVector(TPoint* P2, TPoint* P1){
      TVector V;
      V.vx = P2->x - P1->x;
      V.vy = P2->y - P1->y;
      fprintf(stderr, "GetVector: V.vx: %f V.vy: %f\n", V.vx, V.vy);
      return V;
    }
    
    int main(){
      TPoint P1, P2;
      TVector V;
      double l;
    
      P1.x = .0;
      P1.y = .0;
    
      P2.x=1.;
      P2.y=1.;
    
      V = GetVector(&P2, &P1);
      fprintf(stderr, "main: V.vx: %f V.vy: %f\n", V.vx, V.vy);
    
      l = Vektorlaenge(&V);
      fputs("Langenberechnung durchgeführt\n", stderr);
    
      printf("Vektorlaenge: %2.4f\n", l);
    
      getchar();
      return 0;
    }
    

    Meine Erfahrung hat gezeigt, dass mein Programm mit dem TCC kompiliert sehr schnell ist - schneller als mit VC++2013 inkl. Optimierer. Einziges Manko: OpenMPI wird nicht unterstützt - aber das kommt eh erst später.

    Ich muss sagen, ich bin schwer überrascht. Bist du sicher, dass du deine Messungen korrekt durchgeführt hast? Der ganze Witz an tcc ist schließlich, dass er (d.h. der Compiler selbst) so schnell ist, eben weil er nur minimale Optimierungen durchführt.



  • SeppJ schrieb:

    Reicht nicht eventuell das Quadrat der Länge für dein Vorhaben?

    Ich glaube nicht. Ich muss das Skalarprodukt mehrerer Vektoren mit ein und dem selben Vektor vergleichen. Da spielt nicht nur die Länge, sondern auch der Winkel zwischen den Vektoren eine Rolle. Aber danke für den Hinweis, an der ein oder anderen Stelle konnte ich damit auf eine Wurzel verzichten.

    SeppJ schrieb:

    Ist zwar weit her geholt, aber hast du mal versucht, dies zu variieren und das entstandene Programm direkt auszuführen?

    Scheint nicht so weit hergeholt zu sein, denn genau das habe ich auch schon versucht 🙂 - gleiches Resultat. Ich führe das Programm ja auch nur über NPPEXEC aus. Aber ja, hab die Exe auch mal in Windows angeklickt.

    SeppJ schrieb:

    Ich muss sagen, ich bin schwer überrascht. Bist du sicher, dass du deine Messungen korrekt durchgeführt hast? Der ganze Witz an tcc ist schließlich, dass er (d.h. der Compiler selbst) so schnell ist, eben weil er nur minimale Optimierungen durchführt.

    Um ehrlich zu sein habe ich nichts gemessen. Ich muss in meinem richtigen Programm, wofür ich diese Funktion schreibe, mehrere GB an Daten einlesen und dann verarbeiten. Alleine das Einlesen dauert etwa eine Minute und da merkt man es schon. Ich nehme die Zeit beim Start auf und am Ende, substrahiere diese und gebe das aus. Ich habe aber selbst schon gemerkt, dass das nicht soooo genau ist. Wenn ich nämlich nur eine sehr kleine Datei einlese, wobei der Code dann weniger als eine Sekunde zum Durchlaufen benötigt, zeigt er trotzdem ein paar Sekunden an. Aber wie ich schon geschrieben habe: Ich kann mit den meisten Optionen in VS nichts anfangen und hab da sicher nicht das Optimum eingestellt - Optimierung hab ich aber gefunden.

    Übrigens kann ich eingrenzen, dass es definitiv an der Funktion GetVector liegt. Wenn ich nämlich diese auskommentiere, stürzt das Programm nicht ab.

    Anbei ein Code, der auch mit TCC bei mir wunderbar funktioniert:

    #include <stdio.h>
    #include <math.h>
    
    typedef struct{
        double vx; //x value
        double vy; //y value
    } TVector;
    
    typedef struct{
        double x; //x value
        double y; //y value
    } TPoint;
    
    double Vektorlaenge(TVector* V){return sqrt(V->vx*V->vx + V->vy*V->vy);}
    
    TVector GetVector(TPoint* P2, TPoint* P1){
    TVector V;
    V.vx = P2->x - P1->x;
    V.vy = P2->y - P1->y;
    return V;
    }
    
    int main(){
    TPoint P1, P2;
    TVector V;
    
    P1.x = .0;
    P1.y = .0;
    
    P2.x=1.;
    P2.y=1.;
    
    V.vx = P2.x - P1.x; //Änderung
    V.vy = P2.y - P1.y; //Änderng
    
    //V = GetVector(&P2, &P1); Änderung
    printf("Vektorlaenge: %2.4f\n", Vektorlaenge(&V));
    
    getchar();
    return 0;
    }
    

    Ich habe also nur den Inhalt der Funktion GetVector in die main-Funktion kopiert und die Pfeile durch den Punkt ersetzt... das mit TCC kompilierte Programm liefert 1.4142.



  • One-Man-Army schrieb:

    Hi!

    http://en.wikipedia.org/wiki/Struct_%28C_programming_language%29

    Ich habe es gerade bei mir versucht, das Programm läuft ohne Probleme. Allerdings wundert es mich ein bisschen.
    Guck mal nach ob dein Compiler evtl. ein Problem damit hat, dass du deine Struktur falsch definiert hast.

    typedef struct name { komponente_1, ..., komponente_n }
              variable_1, ..., variable_m;
    

    So sollte es normaler Weise aussehen.
    Seid Ihr euch sicher dass es Standardmäßig mit jedem Compiler funktioniert den Bezeichner ("name") hinter den Strukturrumpf zu schreiben? 😕

    Lg

    Danke, habs versucht... das ändert aber leider nichts.


  • Mod

    CJens schrieb:

    Ich glaube nicht. Ich muss das Skalarprodukt mehrerer Vektoren mit ein und dem selben Vektor vergleichen. Da spielt nicht nur die Länge, sondern auch der Winkel zwischen den Vektoren eine Rolle. Aber danke für den Hinweis, an der ein oder anderen Stelle konnte ich damit auf eine Wurzel verzichten.

    Winkel sind übrigens auch etwas, worauf man in einer Rechnung oft verzichten kann, wenn man nur gründlich nachdenkt, was man wirklich erreichen möchte. Ein Winkel ist eine typische Größe, die man einmal am Ende ausrechnet, wohingegen man beim eigentlichen Algorithmus oft mit dem cos(Winkel) auskommt (Also dem Skalarprodukt. Wobei hier eventuell eine Wurzel nötig ist, zwecks Normierung).

    Um ehrlich zu sein habe ich nichts gemessen.

    Dazu sag ich mal nur: 🙄

    Ich muss in meinem richtigen Programm, wofür ich diese Funktion schreibe, mehrere GB an Daten einlesen und dann verarbeiten. Alleine das Einlesen dauert etwa eine Minute und da merkt man es schon.

    Klingt so, als "misst" du höchstwahrscheinlich nur, dass du das eine Programm direkt ausführst, während beim anderen ein Debugger mitläuft.

    Übrigens kann ich eingrenzen, dass es definitiv an der Funktion GetVector liegt. Wenn ich nämlich diese auskommentiere, stürzt das Programm nicht ab.

    Gut, das ist doch schon einmal eine Spur. Hast du mal mein "Debug"programm aus meinem letzten Beitrag ausgeführt?

    Mit dieser Spur, kann ich das Debugprogramm auch noch einmal erweitern:

    #include <stdio.h>
    #include <math.h>
    
    typedef struct{
      double vx; //x value
      double vy; //y value
    } TVector;
    
    typedef struct{
      double x; //x value
      double y; //y value
    } TPoint;
    
    double Vektorlaenge(TVector* V)
    {
      double l2;
      double l;
      fprintf(stderr, "Vektorlaenge: V->vx: %f V->vy: %f\n", V->vx, V->vy);
      l2 = V->vx*V->vx + V->vy*V->vy;
      fprintf(stderr, "Vektorlaenge: l2: %f\n", l2);
      l = sqrt(l2);
      fprintf(stderr, "Vektorlaenge: l: %f\n", l);
      return l;
    }
    
    TVector GetVector(TPoint* P2, TPoint* P1){
      TVector V;
      fprintf(stderr, "GetVector: P1 %p P2: %p\n", (void*)P1, (void*)P2);
      V.vx = P2->x - P1->x;
      V.vy = P2->y - P1->y;
      fprintf(stderr, "GetVector: V.vx: %f V.vy: %f\n", V.vx, V.vy);
      return V;
    }
    
    int main(){
      TPoint P1, P2;
      TVector V;
      double l;
    
      P1.x = .0;
      P1.y = .0;
    
      P2.x=1.;
      P2.y=1.;
    
      fprintf(stderr, "main: &P1 %p &P2: %p\n", (void*)&P1, (void*)&P2);
    
      V = GetVector(&P2, &P1);
      fprintf(stderr, "main: V.vx: %f V.vy: %f\n", V.vx, V.vy);
    
      l = Vektorlaenge(&V);
      fputs("Laengenberechnung durchgefuehrt\n", stderr);
    
      printf("Vektorlaenge: %2.4f\n", l);
    
      getchar();
      return 0;
    }
    

    (Bitte per Copy&Paste einfügen. Nicht abtippen!)

    Erwartete Ausgabe sollte etwas in dieser Art sein (Konkrete Adressen können natürlich unterschiedlich sein, sie müssen nur in main und GetVector gleich sein):

    main: &P1 0x7fff69441180 &P2: 0x7fff69441170
    GetVector: P1 0x7fff69441180 P2: 0x7fff69441170
    GetVector: V.vx: 1.000000 V.vy: 1.000000
    main: V.vx: 1.000000 V.vy: 1.000000
    Vektorlaenge: V->vx: 1.000000 V->vy: 1.000000
    Vektorlaenge: l2: 2.000000
    Vektorlaenge: l: 1.414214
    Langenberechnung durchgefuehrt
    Vektorlaenge: 1.4142
    

    Beziehungsweise bei dir sollte es abstürzen, aber nicht ohne vorher wertvolle Hinweise preis zu geben.

    Bist du dir auch wirklich 100% sicher, dass das Programm hier im Forum 1:1 dem Programm bei dir entspricht? Die wahrscheinlichste Ursache ist meiner Meinung nach immer noch, dass du uns nicht das richtige Programm zeigst, sondern nur ein ähnliches. Vielleicht auch aus Versehen: Bist du sicher, dass du auch das aktuelle Programm übersetzt und ausführst und nicht eine alte, fehlerhafte Version? Du wärst nicht der Erste, dem das passiert.
    Ein einziges, anders gesetztes Zeichen würde schon alles erklären, da du hier mit rohen Pointern herum jonglierst. Deine Symptome sind auch die typischen Symptome, die man erhält, wenn man dabei etwas falsch macht. Bloß hier im Forum ist alles richtig im Code.

    CJens schrieb:

    One-Man-Army schrieb:

    ...

    Danke, habs versucht... das ändert aber leider nichts.

    Wie schon gesagt wurde, war die Antwort von One-Man-Army falsch. Es ist aber sehr komisch, dass dies nichts geändert haben sollte, denn das Programm wird dadurch falsch und kann nicht mehr funktionieren. Was wieder den Verdacht von oben herauf beschwört, dass du uns nicht den richtigen Code zeigst oder sonstwie falsche Angaben machst - ob absichtlich oder unabsichtlich. Du willst hier Hilfe. Wenn du uns etwas verheimlichst, können wir dir nicht helfen!

    Es liegt wohl an TCC

    Das ist so gut wie ausgeschlossen.


Anmelden zum Antworten