Komischer Zeiger



  • Hallo

    Ich habe heute was gesehen, was mein Verständnis für Zeiger ziemlich durcheinander bringt.

    struct sRequest
    {
      ...
      int Count;
      char Data[];
    };
    
    void foo(char *Data, int Count)
    {
      sRequest Request; 
      Request.Count = Count;
    
      char *IocCommand = new char[sizeof(sRequest) + Count];
      memcpy(IocCommand, &Request, sizeof(sRequest));
      memcpy(IocCommand + sizeof(sRequest), Data, Count);
    
      ...
    }
    


    Sieht für mich so aus, dass ein "Arrayzeiger" nur eine relative Addresse besitzt. Währe das auch mit dieser Deklaration möglich char Data[1] ?

    gruss Patrik



  • Ich nehme an, dein Problem ist, das der String ans Ende von IocCommand kopiert wird und daher, nach dem Rückkopieren der Struct aus IocCommand der Pointer Reqest.Data nicht mehr stimmt. Damit hast du auch recht (afaik sind Pointer nicht inkrementell und selbst wenn, würde trotzdem nach dem memcpy nicht mehr stimmen). Eine Möglichkeit wäre, das der Pointer nach dem Rückkopieren korrigiert wird, zB:

    void Recieve(char *IocCommand)
    {
        sRequest rec;
        char *Data = *IocCommand[sizeof(sReqest)];
        memcpy(&rec,IocCommand,sizeof(sRequest));
        rec.Data = Data;
    }
    

    Könntest du mal verraten, wo du diesen Schnipsel herhast?
    Denn besonders schön ist das ganze nicht.
    Ich nehme an, diese umständliche und unschöne Verpackung einer Struct in ein Char Array ist notwendig, da das ganze versandt werden soll.
    Aber imho wäre es wohl intelligent zumindest Pointer aus der Struct wegzulassen, da diese zwangsläufig invalid werden sobald die Zieldaten verschoben werden.

    Bitte klär mich über funktion der Funktion und sonstige Nebenwirkungen auf, vielleicht blicke ich dann klarer durch.
    MFG ChockoCookie



  • Komischerweise funktioniert das aber, daher auch dieser Thread. Dieses gebastel brauche ich, um eine variable Anzahl von Daten mittels DeviceIoControl() an einen Treiber zu schicken. Mit der Funktion DeviceIoControl() kann man nur eine zusammenhängender Block übergeben. Wenn man zu den Daten noch zusätzliche Informationen braucht kommt man um eine struktur nicht herum. Früher habe ich das ohne Zeiger (char Data[]) geschick, dann musste ich im Treiber den Ort der Daten selbst berechnen char *Data = pRequest + sizeof(struct sRequest);, ist aber nicht besonders schön. Mit der jetztigen Methode geht das einfacher char *Data = &pRequest->Data[0];.

    gruss Patrik



  • Du programmierst nicht zufällig unter DOS? Diese "funktionierende" Methode kann ich mir nur so erklären, das der originale Pointer noch ansprechbar ist. Entweder Programmierst du unter DOS, wo alle Programme im selben Addressraum sind oder unter Windows, falls der Treiber in der selben Instanz wie das Hauptprogramm läuft.
    Versuch mal das du nach dem
    memcpy(IocCommand + sizeof(sRequest), Data, Count);
    den originalen String veränderst. Und sieh was du dann im Treiber bekommst. Dein Pointer zeigt nämlich noch auf den originalen String und den String den du zusätzlich noch hineinkopierst ist genau eines: für die Katz. Wenn das AUCH nicht die Lösung des Rätzels ist, dann ist es wohl wirklich der erste inkrementelle Pointer der Welt ;-).
    MFG ChockoCookie



  • Ich programmiere unter Windows 2000, aber das spielt keine rolle. Probiere doch mal diesen Code.

    struct sRequest
    {
      int Count;
      char Data[];
    };
    
     void foo(char *Data, int Count)
     {
       sRequest Request1;
       Request1.Count = Count;
    
       char *IocCommand1 = new char[sizeof(sRequest) + Count];
       memcpy(IocCommand1, &Request1, sizeof(sRequest));
       memcpy(IocCommand1 + sizeof(sRequest), Data, Count);
    
       sRequest *Test1 = reinterpret_cast<sRequest *> (IocCommand1);
       cout << (int) Test1 << "  " << (int) Test1->Data << "  " << Test1->Data << endl;
    
       char *IocCommand2 = new char[sizeof(sRequest) + Count];
       memcpy(IocCommand2, IocCommand1, sizeof(sRequest) + Count);
    
       memset(IocCommand1, 0, sizeof(sRequest) + Count);
    
       sRequest *Test2 = reinterpret_cast<sRequest *> (IocCommand2);
       cout << (int) Test2 << "  " << (int) Test2->Data << "  " << Test2->Data << endl;
     }
    
    int main()
    {
      char *Str = "Relativer Pointer";
      foo(Str, strlen(Str) + 1);
      return 0;
    }
    

    Was meinst du dazu? 🙂



  • Patrik Müller schrieb:

    Hallo

    Ich habe heute was gesehen, was mein Verständnis für Zeiger ziemlich durcheinander bringt.

    struct sRequest
    {
      ...
      int Count;
      char Data[];
    };
    
    void foo(char *Data, int Count)
    {
      sRequest Request; 
      Request.Count = Count;
    
      char *IocCommand = new char[sizeof(sRequest) + Count];
      memcpy(IocCommand, &Request, sizeof(sRequest));
      memcpy(IocCommand + sizeof(sRequest), Data, Count);
    
      ...
    }
    


    Sieht für mich so aus, dass ein "Arrayzeiger" nur eine relative Addresse besitzt. Währe das auch mit dieser Deklaration möglich char Data[1] ?

    gruss Patrik

    Hallo,


    den Inhalt von Data zugreifen. Dazu haettest du 'Request' als Zeiger definieren
    muessen, dann wie o. Zeile schon zeigt entsprechend fuer 'IocCommand' Speicher
    reseriveren und dann 'Request' auf diesen Verweisen lassen muessen. Dann
    haettest du mittels 'Request->Data[x]' auf den Inhalt von 'Data' zugreifen
    koennen.

    Bei o. Code ist das aber nicht der Fall. 'IocCommand' und 'Request' haben
    nichts miteinander gemeinsam, mal davon abgesehen, dass, wenn du 'IocCommand'
    nach sRequest castest, du auf den Inhalt von 'Data' zugreifen kannst.

    Aber sicherlich nicht mittels 'Request.Data[x]'.

    mfg
    v R



  • Patrik Müller schrieb:

    Ich programmiere unter Windows 2000, aber das spielt keine rolle. Probiere doch mal diesen Code.

    struct sRequest
    {
      int Count;
      char Data[];
    };
    
     void foo(char *Data, int Count)
     {
       sRequest Request1;
       Request1.Count = Count;
    
       char *IocCommand1 = new char[sizeof(sRequest) + Count];
       memcpy(IocCommand1, &Request1, sizeof(sRequest));
       memcpy(IocCommand1 + sizeof(sRequest), Data, Count);
    
       sRequest *Test1 = reinterpret_cast<sRequest *> (IocCommand1);
       cout << (int) Test1 << "  " << (int) Test1->Data << "  " << Test1->Data << endl;
    
       char *IocCommand2 = new char[sizeof(sRequest) + Count];
       memcpy(IocCommand2, IocCommand1, sizeof(sRequest) + Count);
    
       memset(IocCommand1, 0, sizeof(sRequest) + Count);
    
       sRequest *Test2 = reinterpret_cast<sRequest *> (IocCommand2);
       cout << (int) Test2 << "  " << (int) Test2->Data << "  " << Test2->Data << endl;
     }
    
    int main()
    {
      char *Str = "Relativer Pointer";
      foo(Str, strlen(Str) + 1);
      return 0;
    }
    

    Was meinst du dazu? 🙂

    Du hast vergessen, den Speicher wieder freizugeben. Ausserdem gehoert das hier
    weniger ins ANSI C, als viel mehr ins C++ Forum 😉

    mfg
    v R



  • Ich habs vermutlich rausgefunden, was dieses Seltsame Verhalten verursacht:
    Mich hat schon die ganze Zeit irritiert, das man mit Request1.Data zB auf den String zugreifen konnte, ohne ihm jemals den Pointer zugewiesen zu haben.
    Die Lösung: MSVC behandelt char Arrays offensichtlich nicht als Pointer. Man kann zB Request1.Data auch keinen char* zuweisen.
    Das Ergebnis von sizeof(sRequest) ist 4, also die größe eines ints, das heißt, das kein Pointer in der Struct vorhanden ist. Auch auf einem Memdump von Test1 (zB.) sieht man , das da der integer ist und dann sofort der String beginnt. Das bedeutet praktisch, die Pointer von Arrays die man zB mit char foo[] deklariert sozusagen virtuell sind und vom Compiler verwaltet werden ob das AnsiC konform ist, weis ich nicht, ich würde diese verrückte Konstruktion jedenfalls nicht benutzen. Falls ich mich jetzt unklar ausgedrückt habe, sags mir bitte. Ansonsten glaube ich, das das wirklich die Lösung ist.
    MFG ChockoCookie



  • Es scheint, dass du das Rätsel um diesen Zeiger gelöst hast 😉
    Auf die Idee, mit sizeof die grösse der struktur zu überprüfen bin ich nicht gekommen. Aber wenn sizeof 4 zurückgibt, ist da gar kein Platz für einen Zeiger. Überigens funktioniert dieses Beispiel auch mit dem gcc.


Anmelden zum Antworten