Struct Rückgabewert



  • Hi.

    Ich will einen Vektor als Strukt durch eine Funktion erstellen.

    Ich hab mir das so vorgestellt:

    Das Struct

    typedef struct{
        double vx; //x value
        double vy; //y value
    } TVector;
    

    und

    typedef struct{
        double x; //x value
        double y; //y value
    } TPoint;
    

    Die Funktionen:

    double Vektorlaenge(TVector* V){return sqrt(V->vx*V->vx + V->vy*V->vy);}
    

    und

    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;
    }
    

    Naja, bekomme als Antwort Vektorlaenge: 0.0000

    und dann hängt sich der Code auf.

    Wie gebe ich ein Struct korrekt zurück, bzw. wie kann ich das erzeugen?

    Vielen Dank für die Hilfe,
    CJens


  • Mod

    Es gibt keinen offensichtlichen Fehler und wenn man deine Codeteile zusammen kopiert und die noetigen Header ergaenzt, laesst sich das entstehende Programm fehlerfrei ausfuehren (Ausgabe: "Vektorlaenge: 1.4142").

    Folgerung: Du hast uns nicht den Code zu dem fehlerhaften Programm gezeigt. Siehe:
    http://www.c-plusplus.net/forum/304133



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


Log in to reply