C++ std::vector an glibc Funktionen übergeben

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 11.12.2018 11:11:13

Hi Mädels ... Jungs ... :)

z. B. bei der Funktion read muss man ja einen Pointer auf einen Puffer übergeben in dem die gelesenen Daten gespeichert werden.

Code: Alles auswählen

char Puffer[2];
read (iIntDevFile, &Puffer, 2);
Ich suche jetzt nach einer Möglichkeit die Daten effizient in einen C++ Container zu bekommen. Der std::vector würde sich dafür gut eignen ich habe da ein Beispiel im Netz gefunden das aber meiner Meinung nicht ganz richtig ist. Das sah so aus:

Code: Alles auswählen

std::vector Puffer;
read (iIntDevFile, &Puffer[0], iLaenge);
Wenn man aber bei einem vector den Pointer benutzt wird doch kein Speicher für die zu speichernden Daten reserviert.

Meine Lösung jetzt sieht etwas anders aus Funktioniert aber leider auch nicht ganz richtig:

Code: Alles auswählen

std::vector<char> vecDaten;
vecDaten.reserve (2);
read (iIntDevFile, vecDaten.data (), 2);
So hat man zwar die zwei Byte tatsächlich dann im vector gespeichert. Leider liefert die Funktion:

Code: Alles auswählen

vecDaten.size ();
den Wert 0. Der vector mein also das er leer ist. Weiß jemand wie man dem vector erklären kann wie viele Byte in ihm gespeichert wurden oder einen anderen Weg der die Daten ohne Zusätzliches kopieren in einem C++ Container speichert?

owl102

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von owl102 » 11.12.2018 11:14:26

Verwende vecDaten.resize( 2 ) statt vecDaten.reserve( 2 ).

Benutzeravatar
MSfree
Beiträge: 10721
Registriert: 25.09.2007 19:59:30

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von MSfree » 11.12.2018 11:35:28

Noch besser wäre std::basic_iostream statt iIntDevFile zu verwenden. Damit kann man nämlich per >> Operator die Werte direkt in den std::vector streamen.

Siehe auch https://en.cppreference.com/w/cpp, da ist die STL eigentlich gut dokumentiert.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 11.12.2018 12:26:08

Das mit resize muss ich erst noch probiern.

Ich brauche das Filehandle um ioctl Funktionen benutzen zu können. Soweit ich weiß bekommt man das aber von den C++ Stream nicht.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 11.12.2018 15:05:40

Das mit resize geht leider auch nur fast. Es wird dann immer 2 zurückgeliefert auch wenn nur ein Byte mit read gelesen wurde. Das macht es schwer wenn man im weiteren Programm Verlauf feststellen will wie viele Byte der vector enthält. Es ist seltsam wenn man schon auf den vector mit einem Pointer zugreifen kann müsste man auch eine Möglichkeit haben den Größen Zähler richtig zu setzen.

Benutzeravatar
MSfree
Beiträge: 10721
Registriert: 25.09.2007 19:59:30

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von MSfree » 11.12.2018 15:19:22

alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 12:26:08
Ich brauche das Filehandle um ioctl Funktionen benutzen zu können.
Nunja, warum dann nicht so?

Code: Alles auswählen

std::vector<char> vecDaten;
char buffer[2];
int n = read (iIntDevFile, buffer, 2);
for( int i = 0; i < n ; i++ )
{
  vecDaten.push_back( buffer[i] );
}

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 11.12.2018 15:41:21

Wenn ich das richtig sehe werden dann die Daten ein zweites mal kopiert. Das hätte ich gerne vermieden weil es Zeit kostet. Bei dem Beispiel mit zwei Byte sicher nicht so wichtig aber es sind nicht immer nur zwei Byte die gelesen werden.

Benutzeravatar
MSfree
Beiträge: 10721
Registriert: 25.09.2007 19:59:30

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von MSfree » 11.12.2018 17:54:59

alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 15:41:21
Wenn ich das richtig sehe werden dann die Daten ein zweites mal kopiert. Das hätte ich gerne vermieden weil es Zeit kostet.
Nunja, wenn du wüßtest, wie oft Daten in "moderner" Software im Hauptspeicher hin und her kopiert werden, würde dir sofort schlecht werden. Allerdings haben heutige CPUs auch eine Anbindung an den Hauptspeicher, die das Kopieren von einigen Gigabyte pro Sekunde erlaubt, sonderlich zeitintensiv ist das also nicht. Das soll allerdings nicht heißen, daß man nun hemmungslos Daten kopieren soll :mrgreen:

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 11.12.2018 18:28:04

Wohl wahr ...

Aber nur weil alle so Unsinn machen muss ich das ja nicht auch tun. Kopieren ist immer noch teuer im Verhältnis zu anderen Operationen. Es macht schon auch heute noch Sinn es zu vermeiden wenn Möglich. Ich suche halt mal nach möglichen Lösungen. Weil Daten Austausch zwischen glibc und eigenem C++ Programm ja doch recht häufig vorkommen.

Benutzeravatar
MSfree
Beiträge: 10721
Registriert: 25.09.2007 19:59:30

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von MSfree » 11.12.2018 18:34:40

Wenn es dir gerade darum geht, einen IOStream mit einem Filehandle zu öffnen, könntest du auch folgendermassen vorgehen:

Code: Alles auswählen

FILE* f = fdopen( iIntDevFile, "r" );
std::fstream fstr( f );
fstr >> vecDaten;

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 11.12.2018 19:52:55

Ach das geht?
Wusste ich noch nicht leider kann ich es gerade nicht probieren. Kennst Du vielleicht ein Internetseite wo steht wie das geht. Dann hätte ich wenigstens in der zwischen Zeit was zum lesen. Der Suchwuff hat nichts in der Art ausgespuckt.

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von JTH » 11.12.2018 19:56:48

alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 15:05:40
Es ist seltsam wenn man schon auf den vector mit einem Pointer zugreifen kann […]
Die Daten direkt per data() zu bearbeiten und danach die Anzahl der Elemente zu ändern ist wohl nicht der hauptsächlich angedachte Verwendungsweg für std::vector u.ä., aber funktioniert für solche Fälle.
alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 15:05:40
[…] müsste man auch eine Möglichkeit haben den Größen Zähler richtig zu setzen.
Genau, mit resize(). Du kannst nach dem Aufruf von read() resize() ein zweites Mal mit dem Rückgabewert von read() aufrufen, solange der ungleich -1 ist. Das ändert in dem Fall an den Daten nichts und alloziert keinen Speicher neu, es ändert nur die Anzahl der enthaltenen Elemente.
Manchmal bekannt als Just (another) Terminal Hacker.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 11.12.2018 20:06:40

Ach das ist auch gut ich dachte mit resize verwirft der die enthaltenen Daten. Das wird in den Beschreibungen der Funktion die ich gelesen habe nie wirklich angegeben. Das würde dann an der Stelle schon mal helfen ... :)

<Edit>
Weil Du meintest das meine Methode nicht der Verwendungszweck ist. Kennst Du eine andere die ohne nochmal kopieren Daten z.B. von read in einen C++ Container schreibt. Ist ja nicht so das das ein Problem wäre das praktisch nie vorkommt. Gerade auch weil ja C++ laut Erfinder eine Systemnahe Programmierung ermöglichen soll. Irgendwie muss aber dann auch der Übergang von Lowlevel zu Highlevel Programmen effizient möglich sein.
</Edit>

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von JTH » 11.12.2018 20:40:11

alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 20:06:40
Das wird in den Beschreibungen der Funktion die ich gelesen habe nie wirklich angegeben.
Das muss man denk ich eher zwischen den Zeilen zu Complexity und Notes etwa hier [1] herauslesen. Oder kurz in die entsprechenden Header schauen ;) [2] [3]

alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 20:06:40
Weil Du meintest das meine Methode nicht der Verwendungszweck ist. […] Irgendwie muss aber dann auch der Übergang von Lowlevel zu Highlevel Programmen effizient möglich sein.
Die Lösung find ich völlig okay so. C++ und seine Bibliothek versucht dir (vereinfachende) Abstraktionen anzubieten, wie std::vector::push_back() und den Großteil der restlichen vector-Schnittstelle. Es will dir aber bei Bedarf auch direkt den Zugriff „unter die Haube“ erlauben, wie mit std::vector::data().

[1] https://en.cppreference.com/w/cpp/conta ... tor/resize
[2] https://github.com/gcc-mirror/gcc/blob/ ... tor.h#L943
[3] https://github.com/gcc-mirror/gcc/blob/ ... or.h#L1759
Manchmal bekannt als Just (another) Terminal Hacker.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 12.12.2018 15:54:01

Den Vorschlag von MSfree:

Code: Alles auswählen

FILE* f = fdopen( iIntDevFile, "r" );
std::fstream fstr( f );
fstr >> vecDaten;
habe ich jetzt mal ausprobiert mein Compiler mag das aber nicht und sagt beim erzeugen der Instanz "keine bekannte Umwandlung für Argument" scheinbar kann man aus einem FILE keinen Stream erzeugen.

@JHT: Mit dem resize nach dem read auf die echt gelesenen Byte funktioniert es so wie es soll. Ich finde das praktisch weil dann das Objekt sich um die Verwaltung des Speichers kümmert. Speicher selbst verwalten sollte man nur tun wenn wirklich nichts anderes hilft.

Danke für eure Hilfe ... :)

owl102

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von owl102 » 12.12.2018 17:54:00

JTH hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 20:40:11
Die Lösung find ich völlig okay so. C++ und seine Bibliothek versucht dir (vereinfachende) Abstraktionen anzubieten, wie std::vector::push_back() und den Großteil der restlichen vector-Schnittstelle.
Die Lösung von MSfree finde ich nicht ok. Wenn man die Größe weiß, ist es IMHO sträflich bei einem std::vector mit push_back() zu arbeiten. Wenn schon umkopieren, dann resize() + Array-Zugriff (oder std::copy()), ansonsten wird std::vector intern x-mal den Speicher neu anfordern/freigeben und umkopieren, weil das Array ja dynamisch immer größer wird.

Der Argumentation "Nunja, wenn du wüßtest, wie oft Daten in "moderner" Software im Hauptspeicher hin und her kopiert werden, würde dir sofort schlecht werden." mag ich auch nicht folgen. Wenn man schon weiß, wie es mit weniger umkopieren geht, sollte man das schon auch so machen.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 12.12.2018 18:18:26

JTH meinte da meine Lösung: den Pointer auf die Daten in dem vector an die read Funktion zu übergeben. Bevor man das aber tut muss man mit resize dem vector auf eine passende Speicher größe bringen. Sollte read aber wegen erreichen des EOF eine kleiner Menge an Byte lesen muss man mit einem zweiten resize den vector auf die wirkliche größe verkleinern.

Bisher hat sich keine bessere Lösung für das Problem gefunden.

Das in vielen Software Projekten oft nur Daten kopiert werden weil den anderen Teil eine andere Abteilung macht stimmt schon. Rechenzeit zu verschwenden ist leider Modern. Green IT endet immer bei der Hardware das Software auch Strom verschwenden kann ist noch nicht in viele Experten Köpfe vorgedrungen.

Benutzeravatar
bmario
Beiträge: 1256
Registriert: 05.09.2007 12:15:47
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Dresden

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von bmario » 13.12.2018 09:18:51

Ich antworte direkt mal auf den OP, hier kam ja teilweise echt komische sSachen. 8O
alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 11:11:13
Ich suche jetzt nach einer Möglichkeit die Daten effizient in einen C++ Container zu bekommen. Der std::vector würde sich dafür gut eignen ich habe da ein Beispiel im Netz gefunden das aber meiner Meinung nicht ganz richtig ist. Das sah so aus:

Code: Alles auswählen

std::vector Puffer;
read (iIntDevFile, &Puffer[0], iLaenge);
Wenn man aber bei einem vector den Pointer benutzt wird doch kein Speicher für die zu speichernden Daten reserviert.
Du hast recht, so wird kein Speicher allokiert und der vector nicht auf die richtige Größe gesetzt. Das hat aber mit dem Pointer nichts zu tun. Diese Notation hat man vor C++11 benutzt, da gab es schlich die data() Memberfunktion noch nicht.

alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 11:11:13
Meine Lösung jetzt sieht etwas anders aus Funktioniert aber leider auch nicht ganz richtig:

Code: Alles auswählen

std::vector<char> vecDaten;
vecDaten.reserve (2);
read (iIntDevFile, vecDaten.data (), 2);
So hat man zwar die zwei Byte tatsächlich dann im vector gespeichert. Leider liefert die Funktion:
Wie die anderen schon angemerkt hatten, fehlt hier nur noch das resize() des vectors.

Code: Alles auswählen

std::vector<char> vecDaten;
vecDaten.reserve (2);
auto size = read (iIntDevFile, vecDaten.data (), 2);
vecDateb.resize(size);
Aber, wie es halt immer ist, der Teufel steckt halt im Detail. Der erste Satz in der manpage von read() lautet:
read() attempts to read up to count bytes
Das heißt, mal abgesehehn vom einen echt Fehlerfall, kann read() auch jederzeit abbrechen bevor alle Daten aus der Datei gelesen wurden, oder bevor die Anzahl an angefragten Bytes gelesen wurden. Außerdem würde man aus Effizienzgründen nicht nur zwei Bytes lesen wollen.

Eine richtige Lösung würde mittels reserve() einen hinreichend großen Puffer anlegen, read() in einer Schleife ausführen und den Rückgabewert überprüfen. Sind alle Daten gelesen wurden oder EOF erreicht, kann die Schleife verlassen werden. Womöglich hat man nun zuviele Bytes gelesen, nicht nur dass man dann den vector wieder verkleinern muss, hat man zusätzlich das Problem, was tun mit den angefangenen Bytes vom nächsten logischen Lesevorgang? Im Fehlerfall sollte man damit auch umgehen. Und dann werden aus den zwei Zeilen Code ganz schnell 200 und man fragt sich, ob ioctl diese ganzen Mühen wert war. :wink:
Nichts zu tun ist viel besser,
als mit viel Mühe nichts zu schaffen. - Laotse

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von JTH » 13.12.2018 10:40:00

bmario hat geschrieben: ↑ zum Beitrag ↑
13.12.2018 09:18:51
Wie die anderen schon angemerkt hatten, fehlt hier nur noch das resize() des vectors.

Code: Alles auswählen

std::vector<char> vecDaten;
vecDaten.reserve (2);
auto size = read (iIntDevFile, vecDaten.data (), 2);
vecDateb.resize(size);
Auf den zugrundeliegenden Speicher zuzugreifen, wenn die Größe noch 0 ist, ist allerdings nicht korrekt. std::vector::data() darf in dem Fall z.B. einen nullptr zurückgeben [1]. libstdc++ scheint das auch so zu machen [2] [3]. Das muss schon zweimal resize() sein.

[1] https://en.cppreference.com/w/cpp/conta ... data#Notes
[2] https://github.com/gcc-mirror/gcc/blob/ ... or.h#L1129
[3] https://github.com/gcc-mirror/gcc/blob/ ... or.h#L1810
Manchmal bekannt als Just (another) Terminal Hacker.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 13.12.2018 11:26:08

@bmario:
Ich konnte hier nichts komisches erkennen. Das einzige was nicht ging ist mit dem FILE von dem fdopen einen Stream zu erzeugen.

Das der Pointer auch richtig ist &Puffer[0] ist mir bekannt das hatte ich auch nicht gemeint und steht da auch nicht. In dem gefundenen Beispiel fehlt aber der physische Speicher. Meiner Meinung nach ist damit das Beispiel nicht ganz richtig und das steht da auch. Da es nun aber data () gibt macht es Sinn das zu verwenden.

Das read nicht nur so viele Byte lesen kann wie da sind oder auch wegen anderer Probleme abbrechen kann ist schon klar. Deshalb hatte ich ja gefragt wie man dem vector die Tatsächliche Größe geben kann. Das was aber der read jetzt direkt mit den ioctl zu tun hat weiß ich nicht so genau. Ich brauche die ioctl um die Hardware zu Programmieren um dann mit read die Messdaten zu lesen. Da ein Wert nur zwei Byte groß ist macht es keinen Sinn mehr Daten zu lesen. Klar könnte man das wenn man 1000 Byte liest bekommt man halt 500 mal den gleichen Wert. Daher brauche ich hier auch keine Schleife zum lesen das was Du beschreibst ist dann nötig wenn man große Datenmengen liest z.B. von einer Kamera oder aus Dateien.

Das resize die Daten nicht kaputt macht hatte vorher bei meiner Suche irgendwie übersehen. Aber ganz optimal ist die Lösung trotzdem nicht. Da resize ja wirklich den Speicher im vector kleiner macht und nicht nur merkt wo das letzte Byte mit echten Daten ist. Wenn man mit read in einer Schleife wie von Dir beschrieben Blöcke lesen will muss ich nach jedem lese Vorgang in dem der Puffer nicht voll war diesen neu erzeugen. Seltsam ist das man ja mit reserve Speicher reservieren kann und den dann Füllen. Macht man das über die vector Methoden kann reservierter Speicher und echter Inhalt unterschiedlich groß sein. Wenn man das über den Pointer macht kann man nur den vector physisch auf den vorhandenen Inhalt verkleinern und muss Speicher den man später vielleicht noch braucht freigeben. Deshalb kam mir die Lösung mit resize irgendwie nicht richtig vor. Aber wenn es nicht anders geht mach ich es halt mit zweimal resize. Sieht für mich als Übergang zu einem C++ Programm immer noch besser aus als ein char Array nochmal in was anderes um zu kopieren.

@JTH: Das resize einen nullptr zurückgibt wenn der vector keinen Speicher reserviert hat macht Sinn. Üblicherweise benutzt man den nullptr ja um ungültige Pointer zu Markieren.

Bei reserve macht der da nichts oder hab ich nur nicht die richtige stelle gefunden:
https://github.com/gcc-mirror/gcc/blob/ ... tor.h#L989

Antworten