COLORREF to char*- gibt's was schnelleres als stringstreams?



  • wenn man mal stark vereinfach davon ausgeht dass eine "zeile" zB aus 5 Pixeln besteht und jedes Pixel dieselbe Farbe hat (beispielsweise 1234567) steht in der zu sendenden char* Variable folgendes:

    1234567;1234567;1234567;1234567;1234567

    also ich würde die Größe so ausrechnen(korrigiert mich bitte wenn ich falsch liege):

    sizeof(COLORREF) gibt 4 zurück, deswegen nehme ich mal an dass COLORREF im Speicher 4 Bytes belegt genau wie ein ; in einer char* variable;

    (jetzt geht's schon richtig in Mathe über 😃 )

    sagen wir mal n ist die Anzahl der Pixel pro Zeile:

    das heißt die Größe aller COLOREREF-Werte wäre 4n;
    die anzahl der Strichpunkte ist n-1;
    größe der Strichpunkte ist also 4*(n-1);

    d.h. die Gesamtgröße in Bytes liegt bei 4n+4*(n-1) = 4*[n+(n-1)] = 4*(2n-1);

    edit: muss ich eigentlich das \0 am Ende mitrechnen?

    @hustbaer:

    msdn schrieb:

    int send(
    __in SOCKET s,
    __in const char *buf,
    __in int len,
    __in int flags
    );

    ( http://msdn.microsoft.com/en-us/library/ms740149 )

    der 2.Parameter ist doch eindeutig vom Typ char* -> man kann auch nur daten vom typ char* verschicken oder liege ich da falsch? 😕

    edit2: gibt es eigentlich irgendeine vorgerfertigte Methode um éinen Screen zu machen? aktuell lese ich nämlich jedes Pixel einzeln^^

    edit 3: ist es jetzt performancemäßig besser die char* in bestimmte Stücke zu teilen oder als ein char* zu schicken?

    danke schonmal,
    andi01.



  • @hustbÄr:
    Jo richtig, ich meinte auch nur wenn es sich halt immer um einen minimalen overflow handelt 😉



  • @zeusosc: selbst bei minimalem "overflow" sollte sich nagle's algorithm darum kümmern dass nicht VIEL zu viele pakete verschickt werden.

    send-send-send ist ziemlich unproblematisch.
    send-send-recv kann dagegen zu deutlichen delays führen.

    (wobei mir natürlich klar ist dass irgendwann fast immer ein recv kommt, nur wenn der datenfluss selten genug die richtung wechselt, dann kommt man mit paketen beliebiger grösse eigentlich recht gut durch)



  • @andi01:

    kurzfassung: vergiss dass der typ "char*" ist.

    der zeiger den du da übergibst ist einfach der anfang eines datenblocks (byte-array), und die länge die du übergibst ist die länge dieses datenblocks in bytes.

    (ich hab ehrlich gesage keine ahnung was auf systemen wo char nicht 8 bit hat passiert, also ob die beschreibung der sockets API darauf überhaupt eingeht, aber diese systeme vergessen wir einfach mal. zahlt sich nicht aus darüber nachzudenken.)

    und was ist ein file? ein file ist auch ein datenblock, ein ding was aus lauter bytes besteht. also kannst du alles was du in ein file schreiben kannst auch über nen socket schicken.

    so einfach ist das.

    was COLORREF angeht: angenommen du hast ein array aus 100 COLORREF und willst die *relevanten* daten da drin übertragen:

    void foo()
    {
        COLORREF cols[100];
    
        // EDIT: hier irgendwie daten nach "cols" reinladen
    
        // EDIT: 100 COLORREFs "serialisieren" (ginge auch mit nem fixed-size buffer, da wir hier fix 100 COLORREFs == 300 bytes verschicken)
        std::vector<unsigned char> buffer;
        for (size_t i = 0; i < 100; i++)
        {
            buffer.push_back(GetRValue(cols[i]));
            buffer.push_back(GetGValue(cols[i]));
            buffer.push_back(GetBValue(cols[i]));
        }
        // macht genau 3 byte pro COLORREF
    
        assert(buffer.size() == 300);
    
        int const rc = send(
            socket_handle,
            reinterpret_cast<char const*>(&buffer[0]),
            buffer.size(),
            flags);
        // ...
    }
    

    easy-peasy

    wenn du auf der gegenseite dieses datenstück wieder in ein COLORREF array verwandeln willst, ist das auch nicht schwer

    void bar()
    {
        unsigned char buffer[300]; // wir kennen die grösse ja
    
        unsigned char* recv_ptr = buffer;
        int recv_outstanding = 300;
    
        // 300 bytes vom client empfangen 
        // NOTE: die schleife BRAUCHT man, siehe beschreibung von recv()
        //       (man kann nicht verhindern dass recv() nur ein teil-stück empfängt,
        //        und dann schon zurückkehrt, daher muss man selber "mitzählen" wieviel
        //        schon empfangen wurde und ggf. weitere recv() aufrufe nachschieben)
        while (recv_outstanding > 0)
        {
            int const rc = recv(
                socket_handle,
                reinterpret_cast<char*>(recv_ptr), // EDIT: reinterpret_cast hat hier gefehlt
                recv_outstanding,
                flags);
            if (rc == 0)
            {
                // gegenstelle hat "aufgelegt" -> irgendwie handeln
                // ...
            }
            else if (rc < 0 || rc > recv_outstanding)
            {
                // FEHLER -> irgendwie handeln
                assert(rc == SOCKET_ERROR);
                // ...
            }
            else
            {
                // ein stück daten wurde empfangen (und zwar "rc" bytes)
                recv_outstanding -= rc; // fehlt jetzt weniger
                recv_ptr += rc;         // was noch fehlt muss "weiter hinten" im puffer landen
                // und weiter mit dem nächsten stück...
            }
        }
    
        // und wieder 100 COLORREFs draus machen
        COLORREF cols[100];
    
        for (size_t i = 0; i < 100; i++)
            cols = RGB(buffer[3 * i], buffer[3 * i + 1], buffer[3 * i + 2]); // EDIT: hier stand "col = " statt "cols = " - vertipper
    
        // ferdisch
    }
    


  • andi01 schrieb:

    edit 3: ist es jetzt performancemäßig besser die char* in bestimmte Stücke zu teilen oder als ein char* zu schicken?

    es wird überhaupt nirgends ein "char*" verschickt. ein "char*" ist ein ZEIGER, der ZEIGT nur auf die daten die verschickt werden.
    genauso kannst du zum verschicken der daten den "char*" nicht zerteilen.

    du kannst nur den datenblock in mehrere datenblöcke "zerteilen", und dann jeden einzeln schicken.

    lern bitte dich genauer auszudrücken, das ewigt rumraten "was könnte der noob damit jetzt gemeint haben" ist auf die dauer sehr lästig.

    die antwort auf deine frage ist: es ist besser alles auf einmal zu verschicken.



  • kann ich dann nicht gleich auch COLORREF-Werte wegschicken? dann kann ich mir doch das Konvertieren sparen und gleich eine Zeile als COLORREF-Vector wegschicken oder?

    also ungefähr so:

    vector<COLORREF> zeile;
    
    for(int a=0;a<1200;a++)//mal angenommen 1200 pixel pro zeile
    {
    zeile.push_back(GetPixel(GetDC(0), a, 0));
    }
    
    send(socket, reinterpret_cast<const char*> (zeile), zeile.size(), 0);
    


  • Jo, aber dann sendest du halt ein Byte überflüssig mit, denn COLORREF = unsigned long = 4 Bytes, ein RGB Wert wird aber mit nur 3 Bytes dargestellt.



  • beim Rückkonvertieren macht das aber hofentlich nichts aus oder?

    ok aber wie kriege ich jetzt die empfangenen bytes wieder nach COLORREF?

    wenn ich nur immer einen colorref-wert sende wäre es klar:

    COLORREF recieved;
    char* a=new char[sizeof(COLORREF)];
    recv(socket, reinterpret_cast<COLORREF>(a), sizeof(recieved), 0);
    

    aber wie mache ich das jetzt wenn ich den bei send() nach char* gecasteten vektor wieder als COLORREF haben will?

    so?:

    vector<COLORREF> zeile;
    char* a=new char[sizeof(COLORREF)];
    recv(socket, reinterpret_cast<COLORREF>(a), sizeof(recieved), 0);
    


  • Du benutzt die Variable "zeile" gar nicht 😕

    Wenn immer ein send und recv zusammengehören (kA, hab damit nix am Hut), dann einfach:

    // send
    unsigned long color;
    send(socket, reinterpret_cast<const char*>(&color), sizeof(unsigned long), 0);
    
    // receive
    unsigned long color;
    recv(socket, reinterpret_cast<char*>(&color), sizeof(unsigned long), 0);
    


  • Checker! schrieb:

    Du benutzt die Variable "zeile" gar nicht 😕

    Wenn immer ein send und recv zusammengehören (kA, hab damit nix am Hut), dann einfach:

    // send
    unsigned long color;
    send(socket, reinterpret_cast<const char*>(&color), sizeof(unsigned long), 0);
    
    // receive
    unsigned long color;
    recv(socket, reinterpret_cast<char*>(&color), sizeof(unsigned long), 0);
    
    send(socket, reinterpret_cast<const char*>(&color), sizeof(unsigned long), 0);
    

    ... ein bisschen kurz die nachricht oder ?

    grüüße



  • ja klar, wenn ich nur einen COLORREF-Wert gleichzeitig senden würde könnte ich das so machen.

    das problem ist doch dass ich den vector<COLORREF> mit mehreren Werten einfach nach const char* gecastet und verschickt habe;

    d.h. ich kann das von recv() empfangene(nämlich mehrere COLORREF-Werte) doch nicht in eine COLORREF-Variable stecken 😕

    irgendwie muss das doch auch wieder in einen vector oder zumindest ein array...

    edit: davon mal ganz abgesehen kann ich nicht einfach einen vector nach char* casten, der Kompiler sagt nämlich selbst bei einem reinterpret_cast eine Lonvertierung sei unmöglich.

    obige Möglichkeit zum Senden ist demnach falsch. muss ich also jedes einzelne element des vektor extra casten und senden oder wie geht das dann?

    also meine Lösung würde momentan so aussehen:

    //send:
    for(int y=0;y<1500;y++)
    {
    for(int x=0;x<1500;x++)
    {
    COLORREF farbe=GetPixel(GetDC(0), x, y);
    send(socket, reinterpret_cast<const char*>(farbe), sizeof(COLORREF), 0);
    }
    }
    
    //recv:
    for(int y=0;y<1500;y++)
    {
    for(int x=0;x<1500;x++)
    {
    COLORREF farbe;
    char* empfangen=new char[sizeof(COLORREF)];
    recv(socket, empfangen, sizeof(COLORREF), 0);
    farbe=reinterpret_cast<COLORREF>(farbe);
    }
    }
    

    stimmt das dann so?



  • Lies noch mal die letzten beiden Beiträge von @hustbaer.

    zB.

    // send
    unsigned long colors[3] = { 1, 2, 3 };
    send(socket, reinterpret_cast<const char*>(colors), sizeof(colors), 0);
    
    // receive
    unsigned long colors[3];
    recv(socket, reinterpret_cast<char*>(colors), sizeof(colors), 0);
    


  • in meinem code hat noch ein reinterpret_cast gefehlt, sowie ein vertipper war drin. hab ich nachgetragen sowie noch ein paar kommentare hinzugefügt.

    und flags ist üblicherweise 0 für alle die sich wundern was sie da mitgeben sollen.

    @Checker!:
    siehe nachgetragenes kommentar vor der recv()-schleife: die braucht man, sonst bekommt man (schwer zu debuggende) probleme. recv() wartet nämlich nicht bis "size" bytes empfangen wurden, sondern kommt u.u. schon zurück nachdem erst ein byte empfangen wurde.
    -> schleife



  • andi01 schrieb:

    edit: davon mal ganz abgesehen kann ich nicht einfach einen vector nach char* casten, der Kompiler sagt nämlich selbst bei einem reinterpret_cast eine Lonvertierung sei unmöglich.

    kauf dir ein C++ buch und lern erstmal die grundlagen.

    oder schreib wenigstens richtig ab:

    std::vector<MEIN_POD_TYP> vec;
    
    v.push_back(MEIN_POD_TYP(1));
    v.push_back(MEIN_POD_TYP(2));
    v.push_back(MEIN_POD_TYP(3));
    
    char* char_ptr = reinterpret_cast<char*>(&vec[0]); // so geht's
    //char* char_ptr = reinterpret_cast<char*>(vec); // so nicht
    


  • @hustbaer
    Achso, aber nur mit dem TCP, oder?



  • so, ich habe jetzt mal versucht hustbaers codebeispiel auf S.2 zu kompilieren, foo() funktioniert, bei bar() kommt aber noch ein Fehler vom Compiler in Z.44:

    MS Visual C++ 2008 EE schrieb:

    (44) : error C2440: '=': 'COLORREF' kann nicht in 'COLORREF [100]' konvertiert werden

    sollte wahrscheinlich cols[i] heißen 😉

    ich teste es mal schnell ob das senden jetzt geht



  • @hustbÄR:

    Hi,
    ich habe schon öfters gesehen dass auf den datenbereich von STL Komponenten referenziert wird, man sollte aber nicht davon ausgehen dass der allocierte Speicherbereich von STL' komponenten in Reihe liegt. Sollte es nämlich zu einer höheren fragmentation des Heaps kommen, wäre die folge das bei der iteration deines gecasteten ptr'S ein bekanntes 0x00000005 kommt.

    Ansonsten braucht man auch kein reinterpret_cast, sondern kopiert ainfach die addresse von einem pointer zum anderen....(Wenn der inhalt nicht konvertiert werden soll...)

    Es gäbe aber noch eine Alternative:

    typedef	union _ta{
    COLORREF _farbe;
    char a[4];
    } BLUB,*LPBLUB;
    
    LPBLUB _sendMeBabY=(LPBLUB)malloc(12*sizeof(COLORREF));
    _sendMeBabY[0]._farbe=0x0044444;
    char* _Snd=(_sendMeBabY[0].a);
    //Speicher bereich:
    //a[0]= 0x44
    //a[1]= 0x44
    //a[2]= 0x04
    //a[3] = 0x00
    

    Seid gegrüßt und einen schönen tag der Arbeit 😃



  • @zeusosc
    So richtig hässlich!
    Es ist garantiert, dass die Elemente von std::vector im Speicher hintereinander liegen.



  • zeusosc schrieb:

    @hustbÄR:

    Hi,
    ich habe schon öfters gesehen dass auf den datenbereich von STL Komponenten referenziert wird, man sollte aber nicht davon ausgehen dass der allocierte Speicherbereich von STL' komponenten in Reihe liegt. Sollte es nämlich zu einer höheren fragmentation des Heaps kommen, wäre die folge das bei der iteration deines gecasteten ptr'S ein bekanntes 0x00000005 kommt.

    Falsch. Der Standard garantiert dieses Verhalten, und alle STL Implementierungen die ich kenne setzen das auch korrekt um.

    Ansonsten braucht man auch kein reinterpret_cast, sondern kopiert ainfach die addresse von einem pointer zum anderen....(Wenn der inhalt nicht konvertiert werden soll...)

    Es gäbe aber noch eine Alternative:

    typedef	union _ta{
    COLORREF _farbe;
    char a[4];
    } BLUB,*LPBLUB;
    
    LPBLUB _sendMeBabY=(LPBLUB)malloc(12*sizeof(COLORREF));
    _sendMeBabY[0]._farbe=0x0044444;
    char* _Snd=(_sendMeBabY[0].a);
    //Speicher bereich:
    //a[0]= 0x44
    //a[1]= 0x44
    //a[2]= 0x04
    //a[3] = 0x00
    

    Sinnloser Scheissendreck. Und AFAIK ist nichtmal garantiert dass es funktioniert.



  • Bezüglich "Union Hack":

    Sinnloser Scheissendreck. Und AFAIK ist nichtmal garantiert dass es funktioniert.

    Korrekt, das ist nicht garantiert. Garantiert ist nur dass lesen/schreiben von derselben Variable funktioniert.
    Simon


Anmelden zum Antworten