2009-01-13 8 views
44

Im Allgemeinen, was ist der beste Weg, um binäre Daten in C++ zu speichern? Die Möglichkeiten, soweit ich das beurteilen kann, sind fast auf die Verwendung von Strings oder Vektor <char> s. (Ich werde die Möglichkeit von char * s und malloc() s weglassen, da ich mich speziell auf C++ beziehe)."Richtige" Möglichkeit, binäre Daten mit C++/STL zu speichern

Normalerweise verwende ich nur eine Zeichenfolge, aber ich bin mir nicht sicher, ob Overheads, die ich vermisse, oder Konvertierungen, die STL intern tut, die mit der Vernunft von Binärdaten durcheinander bringen könnten. Hat jemand irgendwelche Hinweise (har) zu diesem Thema? Vorschläge oder Vorlieben auf die eine oder andere Weise?

Antwort

38

Vektor von Char ist nett, weil die Erinnerung contigious ist. Daher können Sie es mit vielen C-APIs wie Berkley-Sockets oder Datei-APIs verwenden. Sie können zum Beispiel Folgendes tun:

std::vector<char> vect; 
    ... 
    send(sock, &vect[0], vect.size()); 

und es wird gut funktionieren.

Sie können es im Wesentlichen wie jeden anderen dynamisch zugewiesenen Zeichenpuffer behandeln. Sie können nach oben und unten suchen, um nach magischen Zahlen oder Mustern zu suchen. Sie können es teilweise analysieren. Zum Empfangen von einem Socket können Sie sehr einfach die Größe ändern, um weitere Daten anzuhängen.

Der Nachteil ist die Größenänderung ist nicht sehr effizient (Größe ändern oder Vorabstellung vorsichtig) und Löschung von der Vorderseite des Arrays wird auch sehr ineffizient sein. Wenn Sie, sagen wir, sehr oft nur ein oder zwei Zeichen gleichzeitig vor die Datenstruktur legen wollen, kann das Kopieren auf ein Deque vor dieser Verarbeitung eine Option sein. Dies kostet Sie eine Kopie und Deque-Speicher ist nicht zusammenhängend, so dass Sie nicht einfach einen Zeiger auf eine C-API übergeben können.

Bottom Line, lernen Sie über die Datenstrukturen und ihre Kompromisse vor dem Eintauchen, aber Vektor von Char ist in der Regel, was ich sehe in der allgemeinen Praxis verwendet.

+2

gute Antwort. Zum Lernteil: Ich habe vor einiger Zeit ein schönes Bild gefunden, das die Verwendung von Containern zeigt, und es in diese Antwort eingebettet: http://stackoverflow.com/questions/366432/extending-stdlist#366710 –

6

Ich benutze std::string für diese auch, und hatte noch nie ein Problem damit. Ein "Zeiger", den ich gerade eine scharfe Erinnerung an in einem Stück Code gestern erhalten habe: Wenn Sie einen String aus einem Block von Binärdaten erstellen, verwenden Sie das std::string(startIter, endIter) Formular, nicht das std::string(ptr, offset, length) Formular - das letztere macht die Annahme, dass der Zeiger auf eine C-artige Zeichenfolge zeigt, und ignoriert alles nach dem ersten Nullzeichen (es kopiert "bis zu" die angegebenen length, nicht length Zeichen).

+0

Hmmm. Laut http://www.cplusplus.com/reference/string/string/string.html sollte der std :: string (Zeichen * ptr, Offset, Länge) ctor * alle * length Bytes kopieren, sogar einschließlich Nullbytes. Es ist die Zeichenfolge std :: string (Zeichenfolge const &, offset, length), die * bis zu * length bytes kopiert. –

+0

Dies veranlasste mich, es erneut zu suchen, und es scheint, dass * es * kein Konstruktor std :: string (char * ptr, Offset, Länge) * ist. Der Konstruktor, der offset und length benötigt, benötigt eine std :: string als ersten Parameter, so dass er automatisch eine Zeichenkette aus den Bytes konstruierte, die diese abgeschnitten hat. –

+0

Sie haben Recht. Es tut mir leid, ich meinte die std :: string (char * ptr, size_t length) ctor sollte alle Bytes kopieren. –

3

Sie sollten sicherlich einen Container mit char verwenden, aber der Container, den Sie verwenden möchten, hängt von Ihrer Anwendung ab.

Zeichen haben mehrere Eigenschaften, die sie nützlich für das Halten von binären Daten machen: Der Standard verbietet jede "Auffüllung" für einen char-Datentyp, was wichtig ist, weil Sie keine Abfälle in Ihrem binären Layout erhalten. Jedes Zeichen ist auch garantiert genau ein Byte, was es zum einzigen einfachen alten Datentyp (POD) mit gesetzter Breite macht (alle anderen sind in Bezug auf obere und/oder untere Grenzen spezifiziert).

Die Diskussion über geeignete STL-Container, mit denen die Zeichen gespeichert werden, wird gut von Doug oben behandelt. Welche Sie benötigen, hängt ganz von Ihrem Anwendungsfall ab. Wenn Sie nur einen Block von Daten halten, die Sie durchlaufen, ohne spezielle Lookup-, Append/Remove- oder Splice-Anforderungen, würde ich Vektor bevorzugen, was Ihre Absichten deutlicher macht als std :: string, was viele Bibliotheken und Funktionen annehmen werden enthält eine Null-terminierte C-Style-Zeichenfolge.

8

Das größte Problem mit Std :: String ist, dass der aktuelle Standard nicht garantiert, dass der zugrunde liegende Speicher zusammenhängend ist.Es gibt jedoch keine bekannten STL-Implementierungen, bei denen der String nicht zusammenhängend ist, so dass er in der Praxis wahrscheinlich nicht fehlschlägt. Tatsächlich wird der neue C++ 0x-Standard dieses Problem beheben, indem er festlegt, dass std :: string einen zusammenhängenden Puffer wie etwa std :: vector verwendet.

Ein weiteres Argument gegen string ist, dass sein Name darauf hinweist, dass es eine Zeichenfolge enthält, keinen binären Puffer, der Verwirrung bei denen verursachen kann, die den Code lesen.

Das sagte, ich empfehle Vektor auch.

Verwandte Themen