Pointer auf Element in deque?
-
Hi
Ich arbeite gerade an einer kleinen USB-HID-Lib.
Folgende Zeilen bereiten mir allerdings Probleme:
std::deque< char > *def_vec = getData(); int vecSize = def_vec->size(); // Größe der zu schreibenden Daten int repLen = Capabilities.OutputReportByteLength - 1; // Größe eines Datenblocks für die Übertragung if( ( vecSize % repLen ) != 0 )// Falls nötig... { // ...Größe anpassen def_vec->resize( ( int( vecSize / repLen ) + 1 ) * repLen, 0 ); } // Das erste Byte wird vom Treiber verarbeitet und nicht gesendet def_vec->push_front( 0 ); for( unsigned int i = 0; i < ( def_vec->size() - 1 ); i += repLen ) { // Erstes Byte auf 0 setzen (*def_vec)[i] = 0x00; // Daten schreiben bResult = WriteFile( hDevice, &(*def_vec)[i], // hier ist das Problem Capabilities.OutputReportByteLength, &numBytesReturned, &HidOverlapped ); bResult = WaitForSingleObject(ReportEvent, 200); }
Das Problem ist dass der erste gesendete Block immer Müll ist.
Ich habe jetzt herausgefunden dass das an der Zeile def_vec->push_front( 0 ); liegt. Wenn ich diese auskommentiere werden die Daten richtig gesendet.
Wenn man sich den internen Aufbau eines std::deque veranschaulicht ist auch klar warum das fehl schlägt.
Durch den Befehl push_front wird ja intern ein zweites Array angelegt welches an einer anderen Stelle im Speicher steht.Ein iterator wäre natürlich die Lösung des Problems. Die Frage ist wie ich den an WriteFile übergebe?
Vielen Dank für alle Vorschläge
mfg
stein
-
Ja, eine
std::deque
garantiert nicht, dass intern das Array in einem Block vorhanden ist. Meistens wird es realisiert, indem man mehrere Blöcke hat. Und du wirst mit den Iteratoren sowas auch nicht anWriteFile
übergeben können. Hier hilft nur einstd::vector
Abhilfe.// Kopie erstellen. std::vector<char> dataToWrite(def_vec->begin(), def_vec->end()); // ... // Daten schreiben bResult = WriteFile(hDevice, &dataToWrite[i], Capabilities.OutputReportByteLength, &numBytesReturned, &HidOverlapped);
Oder statt der Kopie, arbeitest du gleich mit
std::vector
, wenn das möglich ist.Grüssli
-
Hab ich mir fast gedacht dass das nicht gehen wird.
Hatte ursprünglich mit nem vector angefangen aber weil beim Senden halt immer dieses erste Byte vorgehängt und beim Lesen entsprechend gelöscht werden muss bin ich auf deque umgestiegen.
Trotzdem vielen Dank
mfg
-
Kannst du beim
std::vector
nichtpush_back()
verwenden (halt die Reihenfolge umkehren)?
-
Das würde nicht funktionieren da die Daten in der richtigen Reihenfolge übertragen werden müssen.
Oder hab ich dich da falsch verstanden?
mfg
-
deckprob schrieb:
...
... // Das erste Byte wird vom Treiber verarbeitet und nicht gesendet def_vec->push_front( 0 ); ...
Das verstehe ich nicht ... kann es sein, dass Du pop_front() meintest ?
Bzw. warum willst Du Deinem Container eine 0 voranstellen?
Willst Du das erste Byte löschen (=aus dem Container entfernen) oder auf den Wert 0 setzen oder ... ?Gruß,
Simon2.
-
Ich muss ein Byte am Anfang einfügen und dieses auf 0 setzen.
Um Daten über WriteFile an mein USB-Gerät zu senden muss das erste Byte jedes Blocks(Reports) 0 sein.
In dem Beispielcode aus dem ich meinen Code erarbeitet habe stand dazu, dass das erste Byte vom Treiber verarbeitet wird und 0 sein muss.
Wenn ich das richtig verstanden habe ist dieses Byte die ReportID.Ab dem zweiten Block setze ich dazu einfch das entsprechende Byte im Puffer auf 0:
(*def_vec)[i] = 0x00;
Beim ersten Block würde ich damit ja aber die zu sendenden Daten verändern.
Also muss ich am Anfang ein Byte einfügen, was ich über
deque::push_front( wert_ist_eigentlich egal )
machen wollte und jetzt halt über
vector::insert(vector::begin(), wert_ist_egal )
mache.
Konnte ich etwas Licht ins Dunkel bringen?
-
Man muss natürlich auch abwägen, wie wichtig einem die Performance ist und ob häufig einzelne Elemente am Anfang eingefügt werden. Je nachdem lohnt sich vielleicht eine
std::deque
oderstd::list
mehr. Wenn man dann das interne Array braucht, kann man immer noch einenstd::vector
von diesen konstruieren. Das mag zwar Zeit in Anspruch nehmen, aber man muss daran denken, dass das Verschieben aller Elemente im Container auch nicht gerade eine leichtgewichtige Operation ist. Wenn dann noch die gelegentliche Reallokation desstd::vector
s vorkommt, ist man damit sicher auf der besseren Seite.Etwas weiter hergeholt wären auch folgende Möglichkeiten (wahrscheinlich kannst du die nicht brauchen, aber um sie mal genannt zu haben):
- Reverse-Iterator
- Schreiben einer Wrapperklasse, die umgekehrten Zugriff gewährt
- Implementierung eines eigenen Containers, der intern wie ein Array aufgebaut ist, aber am Anfang vorallokiert.
-
Etwas mehr Infos:
Bei dem Projekt handelt es sich wie gesagt um eine kleine USB-HID-Bibliothek.Sie besteht bis jetzt aus 4 Klassen:
USBBaseClass // abstrakt, definiert lediglich ein paar Funktionen die in USBThread und USBInterface gebraucht werden. USBInterface // erbt von USBBaseClass und stellt die Schnittstelle für den Programmierer da USBThread // erbt von USBBaseClass, stellt Thread-Objekt mit Sende/Empfangs-Funktionen bereit. USBData // Datenklasse die den threadsicheren Austausch von Daten zwischen USBInterface und USBThread sicherstellt.
Der Programmierer übergibt seinem Objekt von USBInterface die Daten die er an das Gerät schicken möchte mit Hilfe der Funktion
addWriteData( char * buffer, int length ) // vorläufig, später soll man auch Container übergeben können
Diese reicht buffer an das interne USBData-Objekt weiter welches buffer in einen Container(vorher deque, jetzt vector) packt welcher wiederum in eine queue gepackt wird:
std::queue< container< char > > dataToWrite;
Der Thread guckt jetzt ständig nach ob es neue Daten zum schreiben gibt, falls ja holt er sich diese von dem USBData-Objekt und sendet sie mit der Funktion aus meinem ersten Post an das USB-Gerät.
Ich hoffe soweit ist noch alles klar.
Wie ich schon erwähnt habe muss das erste Byte des Arrays welches an WriteFile übergeben wird 0 sein damit alles funktioniert. Dieses Byte wird nicht an das Gerät gesendet sondern offensichtlich lediglich vom Geräte-Treiber verarbeitet (Report-ID).
Nach den Kriterien von Herrn Josuttis habe ich mich für die Datenspeicherung zunächst für eine deque entschieden (es muss oft am Anfang ein Element gelöscht bzw. eingefügt werden), was aber zu den oben beschriebenen Problemen geführt hat.
Zu den Themen Reverse-Iterator, Wrapperklasse, eigener Container:
Wie ein Reverse-Iterator das Problem lösen könnte ist mir unklar.
Da WriteFile einen blanken Pointer erwartet komme ich an dieser Stelle mit iteratoren nicht weiter und auch an einer anderen Stelle würde sowas keinen Sinn machen.Wrapperklasse: auch hier ist das Problem das WriteFile eben ein klassisches sequenzielles Array erwartet. Ich wüsste nicht wie man das untergraben könnte.
Eigener Container:
Wäre eine Möglichkeit aber wohl mit Kanonen auf Spatzen geschossen.Falls ich da etwas falsch verstanden oder nicht bedacht habe würde ich aber sehr gerne mehr zum jeweiligen Thema hören.
Ich denke auch nicht dass sich diese Stelle als Flaschehals herausstellen könnte.
Die STL ist meiner Erfahrung nach so enorm leistungsfähig dass sich erst bei sehr großen Datenmengen eine Verzögerung auch nur messen lassen sollte und bei solchen Datenmengen ist dann der USB-Bus (ja ich weiß, korrekt müsste es US-Bus heißt weil das B schon für Bus steht aber zum besseren Verständnis schreib ichs so :P) der Flaschenhals.Und ja, ich habe schon darüber nachgedacht einfach beim Speichern der Daten in den Container ein Byte vorzuhängen aber nach meinem Verständnis vom Schichtenmodell sollte die Datenhaltungsschicht keine noch so kleine Aufgabe der Verarbeitungsschicht übernehmen.
Ich denke gerade darüber nach ob man nicht doch eine deque verwenden könnte wenn man den ersten zu sendenen Block umkopiert aber dazu muss ich erstmal ein paar Überlegungen anstellen, Bücher wälzen und mir die Innereien von deque anschauen.
Ich bin auch weiterhin für jeglichen Input dankbar
mfg
-
deckprob schrieb:
Ich muss ein Byte am Anfang einfügen und dieses auf 0 setzen....
Ah! OK - danke.
(bitte nicht persönlich nehmen ... hier sind eine Menge Anfänger unterwegs (was ja auch vollkommen in Ordnung ist), die da noch nicht genau wissen, was sie tun).
Gruß,
Simon2.