Datentyp aus Funktion direkt als Datentyp* (Pointer) übergeben



  • schlauch schrieb:

    Gibt es eine Lösungsmöglichkeit ohne den Umweg einer zusätzlichen lokalen Variablen?

    In C99 sollte es dank Compound Literals mit diesem üblen Hack gehen:

    api_foo((struct MyStruct*)&(struct {struct MyStruct m;}){createMyStruct()});
    

    Wie _matze schon gesagt hat ist das natürlich sinnfrei, weil du an den veränderten Wert von i nicht mehr drankommst.



  • _matze schrieb:

    Wie soll das auch gehen? Wie willst du jemals wieder auf den durch api_foo veränderten Wert zugreifen, wenn du ihn nicht in einer Variablen speicherst? Was du da versuchst, könnte sogar kompilieren und 'funktionieren', aber das struct hört mit dem Ausführungsende von api_foo auf zu existieren, so dass es letztlich unsinnig ist.

    namespace invader schrieb:

    [...]
    Wie _matze schon gesagt hat ist das natürlich sinnfrei, weil du an den veränderten Wert von i nicht mehr drankommst.

    Ich brauche den Wert nach api_foo nicht mehr. Ich möchte eine bestimmte Struktur erzeugen, welche diese Apifunktion als Pointer übergeben haben will. Dafür habe ich mir jetzt eine Hilfsfunktion erstellt, die mir lediglich eine solche Struktur erstellt und nicht jedes mal eine Struktur per Hand erstellt und gefüllt werden muss.

    Also hab ich vielleicht unglücklich ausgedrückt:
    Nach api_foo() benötige ich die "Anonyme" Struktur nicht mehr. api_foo() ließt diese Struktur nur.

    Mir ist jetzt nicht ganz klar warum ich bei api_foo(&createMyStruct()); den Fehler: "'&' requires l-value" bekomme 😞

    Warum geht:

    struct MyStruct myStruct = createMyStruct();
    api_foo(&myStruct);
    

    und das hingegen nicht? :

    api_foo(&createMyStruct());
    

    Eigentlich lasse ich doch nur das Zwischenspeichern in eine lokale Variable weg oder hab ich was übersehen?



  • Das Resultat ist bereits wieder tot, deswegen kannst Du da keine Adresse bekommen.
    Mache es dynamisch.

    struct MyStruct* createMyStruct()
    {
      struct MyStruct* myStruct = malloc(sizeof(struct Mystruct));
      myStruct->i = 0;
      return myStruct;
    }
    

    So, bleibt's am Leben, bis Du's mit mfree wieder zerstörst.

    Ohne lokale Variable... hmm... 😉

    struct MyStruct {int i;};
    
    struct MyStruct* api_foo(struct MyStruct* p)
    {
      p->i = 7;
      return p;
    }
    
    struct MyStruct* createMyStruct()
    {
      struct MyStruct* myStruct = malloc(sizeof(struct Mystruct));
      myStruct->i = 0;
      return myStruct;
    } 
    
    int main()
    {
      mfree(api_foo(createMyStruct()));
      return 0;
    }
    


  • Dynamisch machen wollte ich verhindern, aber danke kannte den Weg über mfree nicht.

    Der Rückgabewert soll auch kein Pointer sein, sondern ein Wert bleiben =/.

    Wenn es am toten Resultat liegen sollte, sollte es doch mit static am Leben bleiben(?):

    struct MyStruct createMyStruct()
    {
      static struct MyStruct myStruct;
      myStruct.i = 0;
      return myStruct;
    }
    

    geht aber mit gleicher Fehlermeldung auch nicht 😕
    stehe wohl immernoch auf dem Schlauch



  • schlauch schrieb:

    Ich brauche den Wert nach api_foo nicht mehr. Ich möchte eine bestimmte Struktur erzeugen, welche diese Apifunktion als Pointer übergeben haben will.

    Warum als Pointer? Mach einfach eine Wertübergabe.



  • Habe auf die Apifunktion keinen Einfluss - ist aus einer Fremdlibrary.

    Versteh auch nicht warum die es als Pointer übergeben haben möchten anstatt als Wert - aber vermutlich um Speicher zu sparen - nur einen Pointer kopieren anstatt eine ganze Struktur mit zig Werten.



  • Sicher, dass die Struktur nicht von der Api-Funktion verändert wird (Stichwort call-by-reference)?



  • Tut sie zumindest laut API-Dokumentation nicht 🙂 - Würde auch keinen Sinn machen. Und selbst wenn sollte es mir egal sein, da ich die Struktur nicht mehr brauche.



  • schlauch schrieb:

    Dynamisch machen wollte ich verhindern, aber danke kannte den Weg über mfree nicht.

    Der Rückgabewert soll auch kein Pointer sein, sondern ein Wert bleiben =/.

    Wenn es am toten Resultat liegen sollte, sollte es doch mit static am Leben bleiben(?):

    struct MyStruct createMyStruct()
    {
      static struct MyStruct myStruct;
      myStruct.i = 0;
      return myStruct;
    }
    

    geht aber mit gleicher Fehlermeldung auch nicht 😕
    stehe wohl immernoch auf dem Schlauch

    Jetzt könnte aber ein Pointer als Rückgabewert funktionieren:

    struct MyStruct* createMyStruct()
    {
      static struct MyStruct myStruct;
      myStruct.i = 0;
      return &myStruct;
    }
    


  • _matze schrieb:

    Was du da versuchst, könnte sogar kompilieren und 'funktionieren', aber das struct hört mit dem Ausführungsende von api_foo auf zu existieren, so dass es letztlich unsinnig ist.

    jein, das lokale objekt existiert zwar nicht mehr, aber es wird eine kopie erstellt, wenn der rückgabewert benutzt wird (daher auch nur für kleine structs sinnvoll):

    struct MyStruct createMyStruct()
    {
      struct MyStruct m;
      m.i = 0xcafebabe;
      return m;
    }
    
    void main (void)
    {
       // funzt
       struct MyStruct m = createMyStruct();
       printf ("%08x\n", m.i);
       // funzt auch
       printf ("%08x\n", createMyStruct().i);
    }
    

    🙂



  • fricky, was du schreibst, ist schon klar. Aber es ging darum, dass ein Zeiger auf diesen Rückgabewert an api_foo übergeben und er dort verändert wird. Und wenn api_foo endet, gibt's auch das struct, auf das gezeigt wurde, nicht mehr. Also ist diese Übergabe und die Benutzung des Zeigers unsinnig, weil man sowieso nie mehr an die Daten rankommt, die man da so schön editiert hat (sieh dir den zuerst geposteten Code an).



  • _matze schrieb:

    ...

    oh sorry, der vorschlag mit 'malloc' war ja garnicht von dir. hab das gedanklich beim überfliegen des threads irgendwie vermischt.
    🙂



  • Ja das erste Beispiel zeigt eigentlich nicht was die Apifunktion tut - kann ich jetzt leider nicht mehr editieren 😕

    Das Problem hat aber soweit ich das sehe bis jetzt noch niemand beantwortet warum 1. geht und 2. nicht 😕

    // 1.
    struct MyStruct myStruct = createMyStruct(); 
    api_foo(&myStruct);
    // 2.
    api_foo(&createMyStruct());
    

    macht für mich einfach keinen Sinn bis jetzt 😕



  • schlauch schrieb:

    Ja das erste Beispiel zeigt eigentlich nicht was die Apifunktion tut - kann ich jetzt leider nicht mehr editieren 😕

    Das Problem hat aber soweit ich das sehe bis jetzt noch niemand beantwortet warum 1. geht und 2. nicht 😕

    // 1.
    struct MyStruct myStruct = createMyStruct(); 
    api_foo(&myStruct);
    // 2.
    api_foo(&createMyStruct());
    

    macht für mich einfach keinen Sinn bis jetzt 😕

    da fehlt dir ein sogenannter 'lvalue', das ist ein objekt, das im speicher vorhanden ist (z.b. ist alles 'lvalue', was ziel einer zuweisung sein kann, steht auf der linken seite davon). rückgabewerte von funktionen sind immer 'rvalues', d.h. du kannst die irgendwas zuweisen, aber nicht die adresse davon nehmen. beispiel:

    int a = 1; // a ist lvalue (hat 'ne adresse), 1 ist rvalue (hat keine adresse)
    ...
    int *a = &1;  // geht nicht, ein literal hat keine adresse
    
    ...
    
    int f(void) {return 1;};
    ...
    int *a = &f();  // geht nicht, ein rückgabewert hat keine adresse
    ...
    int i = f();
    int *a = &i;    // aber so gehts, also rückgabewert einem realen objekt zuweisen und dann die adresse davon nehmen
    

    🙂



  • Danke für die Erklärung - so macht das ein ganzes Stück mehr Sinn 🙂

    Dachte beim Funktionsrückgabewert würde ich auch ein "anonymes Objekt" bekommen auf dem ich wenigstens arbeiten könnte wie mit einer lokalen Variablen - dem ist wohl leider nicht so.
    Bleibt mir wohl nur die Lösung über static struct in der createMyStruct ein einen Pointer als Rückgabewert.
    Werd wohl noch ein bisschen dran grübeln.

    Danke an alle 🙂



  • Warum sträubst du dich eigentlich so, eine Variable zu dem Zweck anzulegen? Ist doch nix Schlimmes dabei. Eine Zeile mehr, was soll's...



  • schlauch schrieb:

    Dachte beim Funktionsrückgabewert würde ich auch ein "anonymes Objekt" bekommen auf dem ich wenigstens arbeiten könnte wie mit einer lokalen Variablen - dem ist wohl leider nicht so.

    bekommste ja auch, aber es hat keine adresse. sowas z.b. geht:

    printf ("%d\n", createMyStruct().i);  // auf member des 'virtuellen objekts' zugreifen
    

    rückgewerte haben keine adressen, weil sie sich zu dem zeitpunkt z.b. noch in irgendwelchen prozessorregisten befinden könnten.

    schlauch schrieb:

    Bleibt mir wohl nur die Lösung über static struct in der createMyStruct ein einen Pointer als Rückgabewert.

    ne, das wär sogar äusserst doof, weil jeder aufruf von 'createMyStruct' immer dasselbe objekt liefern würde. zumindest der name der funktion wäre dann ziemlich irreführend.
    🙂



  • _matze schrieb:

    Warum sträubst du dich eigentlich so, eine Variable zu dem Zweck anzulegen? Ist doch nix Schlimmes dabei. Eine Zeile mehr, was soll's...

    Müsste die API-Funktion von vielen verschiedenen Stellen im Code aufrufen - und da wäre es sehr unschön jedesmal eine Hilfsstruktur pro Funktionsaufruf zu erstellen beziehungsweise aufzufüllen - dachte mit einer Hilfsfunktion die das für mich erledigt wär es einfacher und sauberer 🙂

    ;fricky schrieb:

    schlauch schrieb:

    Bleibt mir wohl nur die Lösung über static struct in der createMyStruct ein einen Pointer als Rückgabewert.

    ne, das wär sogar äusserst doof, weil jeder aufruf von 'createMyStruct' immer dasselbe objekt liefern würde. zumindest der name der funktion wäre dann ziemlich irreführend.
    🙂

    Das stimmt wohl - die Funktion ist aber nur dazu gedacht eine für die API-Funktion neu befüllte Struktur zu erzeugen. Sie wird eigentlich nur beim Aufruf dieser API-Funktion verwendet und die static struct kann in sofern nicht versehentlich mit falschen Werten neu erzeugt und damit überschrieben werden.
    Über den Namen mach ich mir aber besser nochmal Gedanken 🙂



  • schlauch schrieb:

    die Funktion ist aber nur dazu gedacht eine für die API-Funktion neu befüllte Struktur zu erzeugen. Sie wird eigentlich nur beim Aufruf dieser API-Funktion verwendet und die static struct kann in sofern nicht versehentlich mit falschen Werten neu erzeugt und damit überschrieben werden.

    Die Aufrufe der API-Funktion können sich aber nicht überschneiden (Threads), ja?



  • schlauch schrieb:

    Das stimmt wohl - die Funktion ist aber nur dazu gedacht eine für die API-Funktion neu befüllte Struktur zu erzeugen. Sie wird eigentlich nur beim Aufruf dieser API-Funktion verwendet und die static struct kann in sofern nicht versehentlich mit falschen Werten neu erzeugt und damit überschrieben werden.

    mach doch sowas:

    // MyStruct initialisieren
    void setup (struct MyStruct *s)
    {
     s.i = ...;
     ...
    }
    ...
    // in zwei schritten eine neue struct anlegen
    struct MyStruct s;
    setup (&s);
    ...
    

    ^^so erhältste jedesmal eine neue struct wo du sie brauchst.
    wenn am anfang alles 0 sein soll, kannste dir sogar 'ne eigene init-funktion sparen und machst es einfach so:

    struct MyStruct s;
    memset (&s, 0, sizeof(s));
    

    🙂


Anmelden zum Antworten