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

FSA

Community-Fossil

  • Private Nachricht senden

21

18.06.2014, 12:01

Zum Thema Endianness: Du kannst einen Integer (vorzugsweise mit fester Größe) erstellen und das erste Byte auslesen. Wenn es eine 1 ist, ist es ein little Endian System.
In etwas so:

C-/C++-Quelltext

1
2
3
4
5
6
bool IsLittleEndian()
{
    int16_t val = 0x1;
    char* fstByte = (char*)&val;
    return fstByte[0] == 1;
}

Ich hoffe ich habe keinen Fehler gemacht :P
EDIT: Wenn char und int16_t aus irgendeinem Grund gleich groß sind, dann wird das ganze nicht funktionieren.

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

Evrey

Treue Seele

Beiträge: 245

Beruf: Weltherrscher

  • Private Nachricht senden

22

18.06.2014, 12:05

Habe mal ein Stück meiner VM angehängt. Der Header prüft die Endianness zur Compile-Zeit. Zusammen gemopst anhand dieser Liste. Zur Laufzeit kannste das mit 'nem union testen.

Bits müssen im Übrigen nicht getauscht werden. Nur die Bytes, wenn du zwischen Little und Big Endian wechselst. Middle Endian, auch PDP-Endian genannt, ist ein ganz abgefahrenes Format aus der Steinzeit. Kannste ignorieren.

char ist unter Garantie die kleinste adressierbare Einheit des Rechners, und das ist so ziemlich überall ein einziges Byte. Muss es jetzt auch sein, weil char != char16_t != char32_t. float ist auch auf fast aller Hardware ein 32bit-Float und double fast überall 64bit-Float. Genauer gesagt kenne ich keine Hardware, bei der das nicht der Fall ist. Hardware ohne FPU ausgenommen. Die zählt nicht.
»Evrey« hat folgende Datei angehängt:
  • endian.hpp (2,87 kB - 50 mal heruntergeladen - zuletzt: 01.05.2024, 00:02)

C-/C++-Quelltext

1
2
3
4
int main(int _argc, char** _argv) noexcept {
  asm volatile("lock cmpxchg8b %eax");
  return 0;
} // ::main
(Dieses kleine Biest vermochte einst x86-Prozessoren lahm zu legen.)

=> Und er blogt unter Hackish.Codes D:

23

18.06.2014, 16:49

So, dank eurer Hilfe hab ich endlich die Ansätze verstanden und habe mir mit diesen eine Serializable Klasse gebastelt.
Aber trotzdem habe ich noch ein paar Fragen... Ich hoffe ich nerve keinen. :P

Und zwar habe ich vorhin auf stackoverflow eine interessante Methode zum vertauschen von Bytes gefunden:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <algorithm>

template <class T>
void endswap(T *objp)
{
  unsigned char *memp = reinterpret_cast<unsigned char*>(objp);
  std::reverse(memp, memp + sizeof(T));
}

file.read( reinterpret_cast<char*>(&i_var) , sizeof(int) );
endswap( &i_var );
file.read( reinterpret_cast<char*>(&d_var) , sizeof(double) );  
endswap( &d_var );
cout << i_var << " " << d_var << endl;

Quelle: http://stackoverflow.com/questions/38239…m-a-binary-file

Die Methode oben sowieso die Methoden von Evrey`s Headerdatei scheinen ja für native
Datentypen zu funktionieren, nur funktioniert das auch mit einem Objekt?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
struct Baum
{
    uint32_t alter;
    uint32_t art;
    // ...
};

Baum tanne;
file.write(reinterpret_cast<char*>(&tanne) , sizeof(Baum));

Denn da stellt sich mir die Frage, wie wird ein Objekt binär abgespeichert?
Als ganzes oder werden die Attribute einzeln rein geschrieben?

Wenn es als "ganzes" gespeichert wird, funktioniert der obige Byteswap, richtig?

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

24

18.06.2014, 17:05

Deine Methode hat nur den Nachteil das sie deutlich uneffizienter ist.
Für Objekte funktioniert sowieso keine auf Bytevertauschen basierende Methode. Es ist ein Unterschied ob du jeweils die 4er-Byte-Tupel umdrehst oder die Bytes insgesamt. Kannst du dir ja einfach selbst vorstellen. Mit deinem Beispiel wenn tanne = Baum{alter = 23, art = 8}; ist auf Little Endian in Hexeditor ansicht der Datei oder Speicherauszug: 17 00 00 00 08 00 00 00. In Big Endian wären die Integer anders herum: 00 00 00 17 00 00 00 08. Wenn du allerdings einfach alle Bytes umdrehst, stimmt logischerweise die Reihenfolge nicht mehr: 00 00 00 08 00 00 00 17
Du musst jeden einzelnen Wert vor dem Schreiben einzeln umdrehen. Insbesondere wirst du ja auch nicht nur diesen einen Typ(std::uint32_t) verwenden.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

25

18.06.2014, 18:47

Beim direkten "in-einem-Rutsch"-Schreiben von struct-Instanzen musst du nochmal aufpassen!
Der Compiler kann mehr oder weniger nach Belieben Lücken zwischen den einzelnen Elementen einfügen, wenn er das für gut hält (Alignment).
Das ist also wieder plattformabhängig. Also ja, du solltest jedes Element einzeln schreiben.

Evrey

Treue Seele

Beiträge: 245

Beruf: Weltherrscher

  • Private Nachricht senden

26

18.06.2014, 18:52

Du brauchst ja beim De-Serialisieren wieder die Konstruktoren. Nutze doch die? Z.B. so:

Quellcode

1
2
3
4
5
6
7
8
9
10
struct my_vector {uint32_t x,y,z;};

std::istream& operator>>(std::istream& _is, my_vector& _v) {
  uint32_t x,y,z;
  _is >> x;
  _is >> y;
  _is >> z;
  if(NeedsByteswap) {_v = {byte_swap(x), byte_swap(y), byte_swap(z)};}
  else {_v = {x,y,z};}
}

(Keine Garantie auf Fehlerfreiheit. Soll nur das Prinzip zeigen.)

C-/C++-Quelltext

1
2
3
4
int main(int _argc, char** _argv) noexcept {
  asm volatile("lock cmpxchg8b %eax");
  return 0;
} // ::main
(Dieses kleine Biest vermochte einst x86-Prozessoren lahm zu legen.)

=> Und er blogt unter Hackish.Codes D:

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

27

18.06.2014, 19:06

Also das sollte aber nicht funktionieren. Ich habe die ominösen Stream-Klassen von C++ jetzt schon länger nicht mehr verwendet, aber schreibt das nicht die Werte als Text raus? Für binäre Operationen bleiben doch nur "reinterpret_cast" + "write"/"read" Methoden in C++? (Im Optimalfall natürlich noch selbst gekapselt)

Evrey

Treue Seele

Beiträge: 245

Beruf: Weltherrscher

  • Private Nachricht senden

28

18.06.2014, 19:48

Ich nutze die auch sehr selten, aber es gibt doch std::ios::binary? Aber wie gesagt: Der Code soll eher die Idee vermitteln.

C-/C++-Quelltext

1
2
3
4
int main(int _argc, char** _argv) noexcept {
  asm volatile("lock cmpxchg8b %eax");
  return 0;
} // ::main
(Dieses kleine Biest vermochte einst x86-Prozessoren lahm zu legen.)

=> Und er blogt unter Hackish.Codes D:

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

29

18.06.2014, 20:10

Das sollte aber nur dafür sorgen dass kein Konvertierungen zum Beispiel bei Zeilenumbrüche gemacht werden soweit ich das in Erinnerung habe. ("\n" -> "\n\r")

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

30

18.06.2014, 20:15

Also das sollte aber nicht funktionieren. Ich habe die ominösen Stream-Klassen von C++ jetzt schon länger nicht mehr verwendet, aber schreibt das nicht die Werte als Text raus?
Nicht, wenn Du binary streams verwendest.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige