COLORREF to char*- gibt's was schnelleres als stringstreams?
-
Hallo,
ich bin gerade dabei einen COLORREF-Wert nach char* zu konvertieren - ja, es muss leider char* sein weil ich den Wert später über Sockets wegschicke und die Funktion send() ausschließlich char*-Werte annimmt
ich habe das auch schon mit stringstreams geschafft:
COLORREF farbe; string konvertiert; stringstream sstr; sstr<<farbe; sstr>>konvertiert; sstr.clear();das funktioniert soweit, aber einfach viel zu langsam wenn man diese Methode sehr oft ausführt;
z.B. mit itoa() habe ich es schon getestet, das würde sehr viel Zeit sparen, aber leider kommt beim Folgenden Code warum auch immer ein falscher Wert heraus:
COLORREF color; char* konvertert=new char[100]; unsigned int farbe=color;//unsigned weil der wert für int zu lang ist itoa(farbe, konvertiert, 10);//basis 10 für Dezimalwerte string ergebnis=konvertiert; delete[] konvertiert;leider steht jetzt ein anderer Wert in der Variable ergebnis als wenn ich COLORREF mit strigstreams konvertiere, auch wenn es viel viel schneller geht

gibt es also eine Alternative mit akzeptabler performance?
danke schonmal,
andi01.
-
Wie wärs denn mit Memcpy? also das das Bitmuster unverändert in das Char-Array schreiben?
COLORREF farbe; char* acText = new char[sizeof(COLORREF)]; memcpy(acText,&farbe,sizeof(COLORREF)); // Zurück geht das dann genauso: COLORREF farbe2; memcpy(&farbe2,acText,sizeof(COLORREF)); delete[] acText;MfG, Jochen
-
wow, danke
ging ja schnell, genau das hatte ich gesucht 
danke,
andi01.
-
es gibt immer was schnelleres als stringstream
oder sonst "zu fuss" hex formatieren, das geht auch hübsch flott
sonst sprintf
-
Caste es doch einfach.
-
Jo,
new allociert Speicher vom Heap, schneller wär es nur noch wenn du den char gleich auf dem stack ablegst:
COLORREF farbe=0x00444444; char blub[4]; memcpy_s(blub,4,&farbe,4); blub[3]='h'; memcpy_s(&farbe,4,blub,4);grüüüße
-
hm welche der methoden ist denn am schnellsten? memcpy() oder casten?
da ich das ganze in einer schleife ziemlich oft mache ist die Performance wichtig
mfg,
andi01.
-
andi01 schrieb:
hm welche der methoden ist denn am schnellsten? memcpy() oder casten?
da ich das ganze in einer schleife ziemlich oft mache ist die Performance wichtig
Nö. Da du es nachher über's Netz (vermute mal Internet) verschickst ist die Performance eher nicht so wichtig.
Davon abgesehen: wäre vielleicht klüger wenn du gleich ein ganzes Bild auf einmal verschickst?
-
hustbaer schrieb:
Nö
naja ein geschicktes Bild hat mehrere megapixel, wenn man diese Konvertierung also mehrere Millionen mal ausführt dauert es mit stringstreams ca. 10sec, mit beiden oberen methoden ca. 2sek.
ich würde mal sagen dass sich eine Verzögerung von 8sek ganz deutlich merken lässt

hustbaer schrieb:
wäre vielleicht klüger wenn du gleich ein ganzes Bild auf einmal verschickst?
ja, Problem dabei ist dass die Funktion send() nur char* als Parameter akzeptiert und keine fertigen bmp- oder jpeg-dateien^^
deshalb bin ich dazu übergegegangen einen screenshot praktisch "zeilenweise" zu verschicken:
zB schreibe ich erstmal den COLORREF-Wert aller Pixel in der "Zeile" y=0, also der obersten Zeile am Bildschirm, in einen char* pointer mit ; getrennt und schicke diese "Zeilen" einzeln weg, bis ich bei der letzten angekommen bin.
bessere Methoden sind mir allerdings immer willkommen, auch wenn mit grade keine bessere einfällt

-
Jo,
Denk auch an die MTU (Maximum transition Unit), für ne maximale auslastung solltest du ca 1430 bytes auf einmal verwenden, (je nach router einstellung, bei mir {wegen PPP} 1492-40=1452 Nutzdaten), falls Du über 1460 kommst wird der restliche teil in einem seperaten Paket verschickt und der rest mit nullen aufgefüllt bis die minimale paketgröße erreicht ist....
Also net zu viel und net zu wenig auf einmal verschicken

-
andi01 schrieb:
hustbaer schrieb:
wäre vielleicht klüger wenn du gleich ein ganzes Bild auf einmal verschickst?
ja, Problem dabei ist dass die Funktion send() nur char* als Parameter akzeptiert und keine fertigen bmp- oder jpeg-dateien^^
nö.
send ist in dieser hinsicht wie "remote memcpy".
da man ein BMP/JPG/PNG/... problemlos mit memcpy kopieren kann, kann man es auch mit send() versenden. also generell alles was in einem file steht bzw. als 1:1 abbild eines files im speicher steht kann man mit send() verschicken.
natürlich sollte man vorher die grösse mitschicken, damit der empfänger auch weiss wie lange das "file" ist.
schnapp dir also eine library die halbwegs flott bilder komprimieren kann (mit oder ohne verlust, ganz nach belieben) und verschick dann das ganze bild auf einmal.
p.S.: wenn du unkomprimiert verschicken willst, dann solltest du vermutlich einfach alle relevanten bytes in ein grosses char-array packen, und das dann auf einmal verschicken. die COLORREFs direkt zu verschicken macht weniger sinn, da ein COLORREF ein DWORD ist, also 4 byte gross. wobei aber nur 3 relevant sind.
@zeusosc:
"zu viel" ist eher unproblematisch, zumindest wenn es "viel zu viel" ist. wenn ich ein 1 MB stück an send() übergeben wird das u.U. sogar schneller rausgehen als wenn ich das gleiche datenstück in lauter 14xx byte stücken übergebe.
-
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?
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)
-
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