Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

11

03.09.2009, 18:13

Zitat von »"dot"«

Aber auch genauso Vorteile. z.B. ist es meist effizienter im Sinne von braucht weniger Speicherplatz und ist schneller zu lesen/schreiben.
Ja. Nur sind das oft nicht die ausschlaggebenden Punkte. Zum Beispiel wird in einem Spiel die Performance durch Datei-IO-Operationen nicht relevant beeinträchtigt; die Priorität liegt woanders. Speicherverbrauch scheint mir in den meisten Fällen auch nicht wirklich ein Kriterium, da genügend Festplattenspeicher vorhanden ist und - wenn man sich geschickt anstellt und nur das Nötige speichert - auch recht wenig Speicher verbraucht wird. Ein int braucht dann zum Beispiel 7 statt 4 Byte. Bei anderen Dingen wie Strings verliert man hingegen gar nichts.

Die Nachteile würde ich trotzdem nicht unterschätzen.
  • Portabilität ist nahezu unmöglich.
    • Grösse der Datentypen
    • Alignment/Padding
    • Big/Little Endian
    • Zahlenrepräsentation, z.B. durch Zweierkomplement
  • Binäres Schreiben ist nur im Zusammenhang mit POD-Typen möglich, also sehr eingeschränkt in C++. Hingegen arbeiten die Stream-Operatoren objektorientiert und können ganze Klassen einlesen oder ausgeben.
  • Anfälliges Hantieren mit Zeigern und Speicherbereichen, undefiniertes Verhalten kann sehr schnell entstehen (natürlich kein Argument, wenn man genau weiss, was man tut - aber generell fehleranfälliger).
  • Schlechte Debugmöglichkeiten, zum Beispiel kann man seine Daten nicht anschaulich im Text-Editor betrachten.
  • Textdateien können nicht weiterverwendet werden, wenn sich am Aufbau der Klasse etwas ändert.
Ich sage nicht, dass binäres Schreiben grundsätzlich schlecht ist. Es gibt natürlich berechtigte Anwendungsfälle, zum Beispiel wenn Dinge wie Performance tatsächlich relevant sind oder ein 1:1-Abbild erwünscht ist. Aber im Normalfall - insbesondere für Anfänger - rate ich zu einem flexibleren Format, speziell wenn etwas über längere Zeit und auf mehreren Compilern/Plattformen verwendet werden soll.

xardias

Community-Fossil

Beiträge: 2 731

Wohnort: Santa Clara, CA

Beruf: Software Engineer

  • Private Nachricht senden

12

03.09.2009, 18:24

Ein ganz angenehmes Mittelding bietet Google Protocol Buffers. Eine Serialisierungsbibliothek die Daten Binär speichert. Primär für den Einsatz über Netzwerke gedacht, aber lässt sich natürlich genauso gut in Dateien schreiben.

Vorteile:
- Protobuf übernimmt die Behandlung von Portabilitätsproblemen
- Das Serialisieren von Strings z.B..
- Die Syntax ist sehr kompakt und übersichtlich.
- Die Serialisierung arbeitet sehr effizient, da weiterhin Binär gearbeitet wird. Vorteilhaft für Performance und Dateigröße. Der Codierungsaufwand ist sehr gering.
- Protobuf gibts für C++/.NET/Java und Python

Nachteile:
- Man benötigt einen zusätzlichen Compiler, bzw einen Code Generator der aus den Protobuf Dateien (in denen dein Dateiformat beschrieben ist) C code generiert.
- Die Datei ist weiterhin Binär, d.h. nicht ohne weiteres lesbar (Gibt jedoch Tools dafür).

Hier kann man sich das ganze anschauen:
http://code.google.com/intl/de-DE/apis/protocolbuffers/docs/overview.html
Und hier etwas genauer:
http://code.google.com/intl/de-DE/apis/protocolbuffers/docs/cpptutorial.html

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

13

03.09.2009, 18:39

Zitat von »"Nexus"«

Zitat von »"dot"«

Aber auch genauso Vorteile. z.B. ist es meist effizienter im Sinne von braucht weniger Speicherplatz und ist schneller zu lesen/schreiben.
Ja. Nur sind das oft nicht die ausschlaggebenden Punkte. Zum Beispiel wird in einem Spiel die Performance durch Datei-IO-Operationen nicht relevant beeinträchtigt; die
Priorität liegt woanders.


Das würd ich absolut nicht behaupten. Wie gesagt es hängt stark davon ab was du speicherst. Wenn es darum geht ganze Landschaften in Echtzeit aus Dateien zu streamen sind riesige Datenmengen im Spiel und Textdateien absolut fehl am Platz...

Zitat von »"Nexus"«

Speicherverbrauch scheint mir in den meisten Fällen auch nicht wirklich ein Kriterium, da genügend Festplattenspeicher vorhanden ist und - wenn man sich geschickt anstellt und nur das Nötige speichert - auch recht wenig Speicher verbraucht wird. Ein int braucht dann zum Beispiel 7 statt 4 Byte. Bei anderen Dingen wie Strings verliert man hingegen gar nichts.


Klar ist Festplattenspeicher heutzutage im Überfluss vorhanden, allerdings erzeugt gerade die Syntax von XML (Tags, Attribute, etc.) schon einen gewissen Overhead sodass man da nicht mehr unbedingt mit 7 vs. 4 argumentieren kann. Dazu sei gesagt dass ich XML auch super finde und gerne verwende, wenn die Anwendung dazu passt. Ich finde allerdings nicht dass man Text und Binärformate als Konkurrenten sehen sollte. Beide haben Vor- und Nachteile und es gibt mindestens genausoviele berechtigte Anwendungen für das eine wie für das andere...

Zitat von »"Nexus"«

Die Nachteile würde ich trotzdem nicht unterschätzen.
  • Portabilität ist nahezu unmöglich.
    • Grösse der Datentypen
    • Alignment/Padding
    • Big/Little Endian
    • Zahlenrepräsentation, z.B. durch Zweierkomplement
  • Binäres Schreiben ist nur im Zusammenhang mit POD-Typen möglich, also sehr eingeschränkt in C++. Hingegen arbeiten die Stream-Operatoren objektorientiert und können ganze Klassen einlesen oder ausgeben.
  • Anfälliges Hantieren mit Zeigern und Speicherbereichen, undefiniertes Verhalten kann sehr schnell entstehen (natürlich kein Argument, wenn man genau weiss, was man tut - aber generell fehleranfälliger).
  • Schlechte Debugmöglichkeiten, zum Beispiel kann man seine Daten nicht anschaulich im Text-Editor betrachten.
  • Textdateien können nicht weiterverwendet werden, wenn sich am Aufbau der Klasse etwas ändert.
Ich sage nicht, dass binäres Schreiben grundsätzlich schlecht ist. Es gibt natürlich berechtigte Anwendungsfälle, zum Beispiel wenn Dinge wie Performance tatsächlich relevant sind oder ein 1:1-Abbild erwünscht ist. Aber im Normalfall - insbesondere für Anfänger - rate ich zu einem flexibleren Format, speziell wenn etwas über längere Zeit und auf mehreren Compilern/Plattformen verwendet werden soll.


Die Portabilität ist ein Problem, allerdings muss man auch hier relativieren. Sofern es nicht darum geht dass die Dateien auf einer anderen Plattform geschrieben als gelesen werden gibt es hier kein großes Problem und auch wenn muss man "nur" den Code zum lesen/schreiben anpassen. Solange du z.B. nur für den x86 PC programmierst brauchst du dir über Endianess erstmal keine Gedanken machen (wenn die Dateien auf der selben Maschine geschrieben und gelesen werden auch sonst nicht) und selbst wenn verschiedene Plattformen im Spiel sind lässt sich das immer noch mit einer einzeiligen Konvertierungsfunktion lösen. Das Problem mit den Datentypen lässt sich (sofern es überhaupt eines gibt, immerhin gibts im aktuellen C Standard Datentypen mit definierten Größen) einfach über typedefs lösen und Maschinen die eine andere Zahlendarstellung als Zweierkomplement verwenden sind wohl sehr sehr rar (vielleicht irgendwelche Mikrocontroller und DSPs die noch Binary Offset oder sowas unterstützen, aber auf jeden Fall nichts was irgendwie einem PC oder einer Spielekonsole ähnlich ist. Floats währen da vielleicht noch eher ein Problem aber auch da hat sich eigentlich der IEEE 754 Standard durchgesetzt).
Weiters hindert dich niemand dran das binäre schreiben/lesen von komplexeren Objekten zu kapseln (von mir aus auch in einem überladenen << operator), das bisschen hantieren mit Zeigern was dazu nötig ist sollte eigentlich jeder der über den Status eines Anfängers hinaus ist im Schlaf beherrschen. Natürlich sind Binärdateien nicht so anschaulich wie Textdateien und sicher aufwendiger zu debuggen, aber mit einem einigermaßen brauchbaren HEX Editor ist auch das kein größeres Problem.
Das weiterverwenden ist sicher ein sehr viel größeres Problem als z.B. mit XML Dateien aber auch hier hängt alles wieder zu stark vom verwendeten Dateiformat und den gemachten Änderungen usw. ab als das man pauschal sagen könnte dass es unmöglich ist. Wenn du deine XML Struktur grob veränderst kannst du auch mit XML genauso ein Problem bekommen.

14

03.09.2009, 19:15

Zitat von »"dot"«

Das würd ich absolut nicht behaupten. Wie gesagt es hängt stark davon ab was du speicherst. Wenn es darum geht ganze Landschaften in Echtzeit aus Dateien zu streamen sind riesige Datenmengen im Spiel und Textdateien absolut fehl am Platz...
Hm, da hast du Recht. Ich habe jetzt eher an einfache Spielstände gedacht. Bei komplexen Landschaften etc. wäre vielleicht ein Kompromiss angebracht: Für die Portabilität existiert ein entsprechendes Format (muss nicht XML sein), bei einer Anwendung mit einer spezifischen Konfiguration wird das einmalig umgewandelt und in ein effizientes Binärformat gebracht. So kann man die Vorteile beider Möglichkeiten kombinieren.

Zitat von »"dot"«

Die Portabilität ist ein Problem, allerdings muss man auch hier relativieren.
Das mag zwar sein - Fakt ist aber, dass all diese Probleme und der nötige Aufwand zu deren Behebung gar nicht erst entstehen, wenn ein flexibles Format eingesetzt wird. Du triffst hier auch relativ viele Annahmen. Es braucht nicht allzu viel, bis eine von diesen nicht mehr erfüllt ist, und du hast wieder Probleme. Probleme, an die du ohne binäres Schreiben gar nicht erst denken musst.

Zitat von »"dot"«

Weiters hindert dich niemand dran das binäre schreiben/lesen von komplexeren Objekten zu kapseln (von mir aus auch in einem überladenen << operator)
Klar, aber damit entfernt man sich aber wieder vom Vorteil, mehrere Dinge auf einmal auszugeben (manche Leute benutzen diesen Punkt als Argument für binäres Schreiben). Der Aufwand kommt dem eines portablen Formats nahe. Unter Umständen geht Performance durch zusätzliche Überprüfungen/Umwandlungen wieder verloren.

Zitat von »"dot"«

das bisschen hantieren mit Zeigern was dazu nötig ist sollte eigentlich jeder der über den Status eines Anfängers hinaus ist im Schlaf beherrschen. Natürlich sind Binärdateien nicht so anschaulich wie Textdateien und sicher aufwendiger zu debuggen, aber mit einem einigermaßen brauchbaren HEX Editor ist auch das kein größeres Problem.
Die Probleme, die man debuggen muss, resultieren zu einem Teil aber auch aus den Fehlern, welche durch das Pointerhantieren entstanden sind. Klar, ein Fortgeschrittener sollte solche Fehler nicht mehr machen. Tatsache ist, dass es trotzdem immer Fehler gibt, und rohe Zeiger haben nun mal ein gewisses Fehlerpotential. Das kann eingeschränkt werden, indem man eine gewisse Kapselung einbringt. Aber zumindest in diesem Forum habe ich noch nie jemanden gesehen, der das wirklich durchzieht. Im besten Fall wird reinterpret_cast statt C-Casts verwendet...

Natürlich ist ein solches gekapseltes Binärformat durchaus vorteilhaft. Aber was ich so gesehen habe, wollen teilweise selbst fortgeschrittene Programmierer 1:1 roh binär schreiben und erhalten undefiniertes Verhalten, weil sie sich der Gefahren nicht bewusst sind. Vielleicht auch, weil sie sich zu wenig mit essentiellen Grundlagen von C++ befasst haben. Von diesem Standpunkt aus halte ich es für geeigneter, zuerst ein flexibles Format (muss nicht XML sein, Textdateien reichen schon recht weit) zu probieren. Dann zeigt sich immer noch, ob binäres Schreiben besser geeignet ist. Denn in sehr vielen Fällen spielen Geschwindigkeit und Speicherverbrauch eben doch nicht die grösste Rolle, wohl aber Sicherheit und Lauffähigkeit des Programms. Ganz nach dem Prinzip der Premature Optimization.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

15

03.09.2009, 21:11

Zitat von »"Nexus"«

Zitat von »"dot"«

Das würd ich absolut nicht behaupten. Wie gesagt es hängt stark davon ab was du speicherst. Wenn es darum geht ganze Landschaften in Echtzeit aus Dateien zu streamen sind riesige Datenmengen im Spiel und Textdateien absolut fehl am Platz...
Hm, da hast du Recht. Ich habe jetzt eher an einfache Spielstände gedacht. Bei komplexen Landschaften etc. wäre vielleicht ein Kompromiss angebracht: Für die Portabilität existiert ein entsprechendes Format (muss nicht XML sein), bei einer Anwendung mit einer spezifischen Konfiguration wird das einmalig umgewandelt und in ein effizientes Binärformat gebracht. So kann man die Vorteile beider Möglichkeiten kombinieren.


Da stimme ich dir natürlich zu, einfache Maps/Spielstände/etc. lassen sich sicher gut als Textdateien speichern. (der Vorteil der Lesbarkeit könnte sich dann evtl. allerdings auch zu einem Nachteil entwickeln...Cheating usw.). Es gibt natürlich aber auch hier wieder das andere Extrem, ich denke da z.B. an den "Spielstand" eines MMORPG. Von Datenbanken in denen die Accounts von mehreren Millionen Spielern weltweit gespeichert werden würd ohne mit der Wimper zu zucken behaupten dass diese nicht in Textdateien gespeichert sind...

Zitat von »"Nexus"«

Zitat von »"dot"«

Die Portabilität ist ein Problem, allerdings muss man auch hier relativieren.
Das mag zwar sein - Fakt ist aber, dass all diese Probleme und der nötige Aufwand zu deren Behebung gar nicht erst entstehen, wenn ein flexibles Format eingesetzt wird. Du triffst hier auch relativ viele Annahmen. Es braucht nicht allzu viel, bis eine von diesen nicht mehr erfüllt ist, und du hast wieder Probleme. Probleme, an die du ohne binäres Schreiben gar nicht erst denken musst.


Ja klar, die Frage ist aber ob diese Probleme wirklich so schwer zu beherrschen sind. Endianess ist sicher eines der Probleme die am schnellsten auftreten werden, ist aber genauso schnell wieder aus der Welt gschafft. Natürlich setzt das voraus dass man sich dieser Probleme bewusst ist.

Zitat von »"Nexus"«

Zitat von »"dot"«

Weiters hindert dich niemand dran das binäre schreiben/lesen von komplexeren Objekten zu kapseln (von mir aus auch in einem überladenen << operator)
Klar, aber damit entfernt man sich aber wieder vom Vorteil, mehrere Dinge auf einmal auszugeben (manche Leute benutzen diesen Punkt als Argument für binäres Schreiben). Der Aufwand kommt dem eines portablen Formats nahe. Unter Umständen geht Performance durch zusätzliche Überprüfungen/Umwandlungen wieder verloren.


Zitat von »"Nexus"«

Zitat von »"dot"«

das bisschen hantieren mit Zeigern was dazu nötig ist sollte eigentlich jeder der über den Status eines Anfängers hinaus ist im Schlaf beherrschen. Natürlich sind Binärdateien nicht so anschaulich wie Textdateien und sicher aufwendiger zu debuggen, aber mit einem einigermaßen brauchbaren HEX Editor ist auch das kein größeres Problem.
Die Probleme, die man debuggen muss, resultieren zu einem Teil aber auch aus den Fehlern, welche durch das Pointerhantieren entstanden sind. Klar, ein Fortgeschrittener sollte solche Fehler nicht mehr machen. Tatsache ist, dass es trotzdem immer Fehler gibt, und rohe Zeiger haben nun mal ein gewisses Fehlerpotential. Das kann eingeschränkt werden, indem man eine gewisse Kapselung einbringt. Aber zumindest in diesem Forum habe ich noch nie jemanden gesehen, der das wirklich durchzieht. Im besten Fall wird reinterpret_cast statt C-Casts verwendet...


Ich sehe den großen Vorteil von Binärformaten in der maschinennahen Form der Speicherung. Die Möglichkeit mehrere Dinge auf einmal auszugeben halte ich für generell weniger signifikant, vor allem da allein schon die file I/O der Standardlibrary per default gepuffert ist, sofern man also nicht z.B. über spezielle APIs ungepufferte I/O betreibt spart man sich da eigentlich nur den Overhead von ein paar Funktionsaufrufen.
Natürlich bewegt man sich mit Binärformaten immer auf maschinennaher Ebene und damit in der Nähe von (oder sogar bewusst in) undefiniertem Verhalten. Allerdings kann man das eigentlich recht gut und sicher kapseln, wobei dann z.b. Code wie dieser entsteht:

C-/C++-Quelltext

1
2
3
4
  file.write(reinterpret_cast<const char*>(&width), sizeof(width));
  file.write(reinterpret_cast<const char*>(&height), sizeof(height));
  file.write(reinterpret_cast<const char*>(&bits), sizeof(bits));
  file.write(reinterpret_cast<const char*>(&descriptor), sizeof(descriptor));


Gefährliches hantieren mit Pointern ist da imo absolut nicht im Spiel (auch wenn der cast implementierungsabhängig sein mag, auf unterster Ebene muss man eben manchmal Plattformspezifisch programmieren). Zusätzliche Validierungen würd ich mal sagen spielen bei Textformaten eine größere Rolle, in einer Datei die vom User im Texteditor editiert werden kann ist an allen Ecken und Enden sehr viel schneller mal ein Tippfehler drin als in einer rohen Binärdatei.

Zitat von »"Nexus"«

Natürlich ist ein solches gekapseltes Binärformat durchaus vorteilhaft. Aber was ich so gesehen habe, wollen teilweise selbst fortgeschrittene Programmierer 1:1 roh binär schreiben und erhalten undefiniertes Verhalten, weil sie sich der Gefahren nicht bewusst sind. Vielleicht auch, weil sie sich zu wenig mit essentiellen Grundlagen von C++ befasst haben. Von diesem Standpunkt aus halte ich es für geeigneter, zuerst ein flexibles Format (muss nicht XML sein, Textdateien reichen schon recht weit) zu probieren. Dann zeigt sich immer noch, ob binäres Schreiben besser geeignet ist. Denn in sehr vielen Fällen spielen Geschwindigkeit und Speicherverbrauch eben doch nicht die grösste Rolle, wohl aber Sicherheit und Lauffähigkeit des Programms. Ganz nach dem Prinzip der Premature Optimization.


Wie gesagt ich halte Textformate für genauso wichtig und sehr praktisch, vor allem wenn es darum geht dass bestimmte Inhalte leicht einsehbar/editierbar sind (z.B. Konfigurationsdateien usw.).

Sicherlich sind Binärformate evtl. etwas aufwändiger in der Entwicklung, deswegen imo aber nicht weniger nützlich. Es geht einfach darum den passenden Ansatz für das Problem zu wählen. Ich sehe z.B. keinen Sinn dahinter ein Netzwerkprotokoll auf XML aufzubauen (wenngleich das in der Java-Welt irgendwie "in" zu sein scheint), warum sollte man z.B. einiges an zusätzlichem Overhead in Kauf nehmen nur um die Kommunikation zwischen Computern über Medien begrenzter Bandbreite in einem Menschenlesbaren Format abzuwickeln, wo nie ein Mensch (außer vielleicht ein Entwickler oder Cracker) einen Blick drauf werfen wird!?

16

03.09.2009, 21:45

Scheint, als wären wir uns weitgehend einig, dass beide Möglichkeiten ihre Berechtigung haben. Tut mir leid, falls das anfangs nicht so rüberkam. Ich wollte primär Leuten, die noch nicht so vertraut mit den erforderlichen Techniken sind, anraten, zuerst den einfachen Weg über Textdateien zu gehen, um zumindest lauffähige Programme schreiben zu können. Wie gesagt sehe ich ab und zu, dass Binärformate unnötigerweise angewandt werden (d.h. in dem konkreten Fall werden die Vorteile nicht benötigt, dafür überwiegen die Nachteile stark). Dann frage ich mich eben, warum man eine Aufgabe nicht einfacher angeht, wenn man das Gleiche auf eine bessere Weise erreichen kann? Aber eben, das ist auf ein paar Leute anzuwenden und nicht auf die Allgemeinheit.

P.S. Ich würde das noch weiter kapseln: ;)

C-/C++-Quelltext

1
2
3
4
5
template <typename T>
void write_binary(const T& obj)
{
    m_file.write(reinterpret_cast<const char*>(&obj), sizeof(obj)); 
}

Werbeanzeige