Der sizeof Operator liefert falsche Grösse?
-
Gerade der zweite sollte nicht funktionieren!!
Denn da gibst du ja von Hand an, bei welchem Byte dein Integer startet (pDta+2). Also machst du schon vorher irgendwo etwas falsch.
-
Ishildur schrieb:
Weil ich folgenden Code schöner finde
// throw an exception if the signature inside the *.3ds file is invalid DsTokenHeader *pHdr = reinterpret_cast<DsTokenHeader*>(pDta); if(pHdr->ID != 0x4d4d) throw DecoderException(FNC,stHdr); if(pHdr->Size != szSrc) throw DecoderException(FNC,stHdr); pDta += sizeof(DsTokenHeader);Ist vielleicht schöner, hat aber leider ein undefiniertes Resultat. Du gehst hier von einem bestimmten Struktur-Layout aus, das vom Standard nicht garantiert wird und Sache des Compilers ist.
-
ist dein weg nicht gerade hübsch und die größe völlig belanglos...Ok, wie mache ich es hübscher?

-
Ishildur schrieb:
ist dein weg nicht gerade hübsch und die größe völlig belanglos...Ok, wie mache ich es hübscher?

Struktur erstellen. 2 Byte in ID laden, 4 byte in Size laden. Nicht 6 byte direkt in die Struktur laden.
-
@Janjan
Doch genau das zweite funktioniert eben, weil ich dort keine Strukturen verwende, die gepadded werden. Und der pDta Pointer enthält einen Zeiger auf eine Speicheradresse, wo ich vorher das komplette File hineinlese. Und im 3ds File format ist nunmal ein Header: 2 Bytes für die ID und 4 Bytes für die Grösse.
-
@Janjan
So?DsTokenHeader hdr; memcpy(&hdr,pDta,2); memcpy(&hdr.Size,pDta+2,4); // throw an exception if the signature inside the *.3ds file is invalid if(hdr.ID != 0x4d4d) throw DecoderException(FNC,stHdr); if(hdr.Size != szSrc) throw DecoderException(FNC,stHdr); pDta += 6;Bleibt vielleicht noch zu erwähnen, dass ich das ziemlich oft an ziemlich vielen verschiedenen Stellen machen muss...
-
Du programmierst C++, kein C. Also lass das memcpy weg.
hdr.ID = *reinterpret_cast<uint16*>(pDta); hdr.Size = *reinterpret_cast<uint32*>(pDta+2);
-
Aha:
// first copy the header onto the stack (which is an unnecessary and useless overhead by the way, but ok, we are programming C++ ;-) DsTokenHeader hdr; hdr.ID = *reinterpret_cast<uint16*>(pDta); hdr.Size = *reinterpret_cast<uint32*>(pDta+2); // throw an exception if the signature inside the *.3ds file is invalid if(hdr.ID != 0x4d4d) throw DecoderException(FNC,stHdr); if(hdr.Size != szSrc) throw DecoderException(FNC,stHdr); pDta += 6;anstatt:
// throw an exception if the signature inside the *.3ds file is invalid if(*reinterpret_cast<uint16*>(pDta) != 0x4d4d) throw DecoderException(FNC,stHdr); if(*reinterpret_cast<uint32*>(pDta+2) != szSrc) throw DecoderException(FNC,stHdr); pDta += 6;Sag mal, kann es sein, dass du pro Codezeile bezahlt wirst? :p
-
Code 1 hast du die Daten bereits in deiner Struktur und kannst die Struktur weiterverwenden.
Code 2 müsstest du die Daten im nachhinein nochmal in die Struktur kopieren um sie zu verwenden.
-
@Janjan
Hehe nein ist schon klar
Es ist hier ein wenig speziell, da ich die Daten nur ein einziges Mal benötige, da ich ja jedes Token nur ein einziges Mal auslese. Aber du hast natürlich recht, wenn ich die Daten mehrmals benötige, würde ich es auch so machen wie du. Es ist halt reine Faulheit, dass ich gerne ganze Strukturen kopiere, anstatt da jedes Element einzeln, aber dann muss man halt höllisch aufpassen, dass bei den verwendeten Strukturen kein Padding auftritt. Im Zusammenhang mit der Umstellung auf 64bit werden wohl allerdings so einige Dateiimporter nicht mehr funktionieren. Bspw.struct PcmHeader{ int8 RiffSig[4]; int32 WaveformChunkSize; int8 WaveSig[4]; int8 FormaSig[4]; int32 FormatChunkSize; int16 FormatTag; int16 Channels; int32 SampleRate; int32 BytesPerSec; int16 BlockAlign; int16 BitsPerSample; int8 DataSig[4]; int32 DataSize; };Diese Struktur ist 32-bit alignet, es findet IMHO nirgends ein Padding statt. Daher funktioniert ein memcpy problemlos. Bei der Umstellung auf 64bit geht dann leider gar nichts mehr, da heissts dann Member by Member...
-
Möglicherweise irre ich mich, aber ich glaube zu wissen dass dieser Speicherzugriff nach
reinterpret_castvom Standard nicht erlaubt wird. Der Hintergrund ist, dass Speicherzugriffe je nach Architektur nur an korrekt ausgerichteten Adressen ausgeführt werden können. Ein gelesener 32-Bit-Wert muss z. B. an einer 32-Bit-Adresse ausgerichtet sein. Das ist hier nicht garantiert.Falls ich mich irre, werde ich sicher bald korrigiert.
-
Ishildur schrieb:
Diese Struktur ist 32-bit alignet, es findet IMHO nirgends ein Padding statt. Daher funktioniert ein memcpy problemlos.
Zufall. Die Reihenfolge der einzelnen Felder im Speicher ist nicht definiert.
-
Ishildur schrieb:
@Janjan
Hehe nein ist schon klar
Es ist hier ein wenig speziell, da ich die Daten nur ein einziges Mal benötige, da ich ja jedes Token nur ein einziges Mal auslese. Aber du hast natürlich recht, wenn ich die Daten mehrmals benötige, würde ich es auch so machen wie du. Es ist halt reine Faulheit, dass ich gerne ganze Strukturen kopiere, anstatt da jedes Element einzeln, aber dann muss man halt höllisch aufpassen, dass bei den verwendeten Strukturen kein Padding auftritt. Im Zusammenhang mit der Umstellung auf 64bit werden wohl allerdings so einige Dateiimporter nicht mehr funktionieren. Bspw....Diese Struktur ist 32-bit alignet, es findet IMHO nirgends ein Padding statt. Daher funktioniert ein memcpy problemlos. Bei der Umstellung auf 64bit geht dann leider gar nichts mehr, da heissts dann Member by Member...
Code der schlecht programmiert wurde wird nicht mehr funktionieren, da hast du recht.
Wer guten Code produzieren will, der weiß das man nicht direkt aus Strukturen lesen und in Strukturen schreiben darf, genau wegen der Padding Geschichte.
Der Standard schreibt eben nicht vor, dass alle Elemente zusammenhängend im Speicher stehen.
-
@Registrierter Troll
Du machst mir Angst...
Auf deine Aussage habe ich leider keine Antwort, ich bin immer davon ausgegangen, dass jedes Byte im Speicher adressiert werden kann. Unabhängig von der Architektur. Bei 32bit kann ich ja IMHO ca. 4GB speicher addressieren. Eine Konsequenz deiner Aussage währe ja doch dann, dass ich ca. 16BG adressieren könnte, aber halt nur jedes 4te Byte?
-
@Janjan
Viele Tutorials und Bücher, die ich gelesen habe und die Verarbeitung von Binärdaten behandeln, lesen und schreiben direkt in und aus Strukturen aus oder in Dateien...Daher bin ich ehrlich gesagt gerade ein wenig schockiert...

-
Ishildur schrieb:
@Registrierter Troll
Du machst mir Angst...
Auf deine Aussage habe ich leider keine Antwort, ich bin immer davon ausgegangen, dass jedes Byte im Speicher adressiert werden kann. Unabhängig von der Architektur. Bei 32bit kann ich ja IMHO ca. 4GB speicher addressieren. Eine Konsequenz deiner Aussage währe ja doch dann, dass ich ca. 16BG adressieren könnte, aber halt nur jedes 4te Byte?Das ist unsinn. Mag sein, dass eine Architektur nur an jedem 4ten Byte zugreifen kann, aber die Implementierung deines C++ Codes muss dies berücksichtigen. Dann muss eben der geschriebene Maschinencode zur Not 3 byte früher lesen, und die ersten 3 Byte wegwerfen. Darauf musst du dank Standard in deinem Code nicht achten, darauf muss der Compiler für dich achten.

-
Ishildur schrieb:
@Janjan
Viele Tutorials und Bücher, die ich gelesen habe und die Verarbeitung von Binärdaten behandeln, lesen und schreiben direkt in und aus Strukturen aus oder in Dateien...Daher bin ich ehrlich gesagt gerade ein wenig schockiert...

Die machen es schlichtweg falsch. Es gibt leider sehr sehr sehr viele schlechte Tutorials und Bücher...
-
@Janjan
Puuhhhh.... Dank dir kann ich wieder ruhig schlafen
-
Ishildur schrieb:
Auf deine Aussage habe ich leider keine Antwort, ich bin immer davon ausgegangen, dass jedes Byte im Speicher adressiert werden kann. Unabhängig von der Architektur.
Kann es ja auch, aber garantiert funktionieren tut das nur, wenn du wirklich nur byteweise zugreifst.
Bei 32bit kann ich ja IMHO ca. 4GB speicher addressieren. Eine Konsequenz deiner Aussage währe ja doch dann, dass ich ca. 16BG adressieren könnte, aber halt nur jedes 4te Byte?
Nein. Die Konsequenz ist, dass ein 32-Bit-Wert nur dann in einem 32-Bit-Zugriff gelesen werden kann, wenn er an durch 4 teilbaren Adressen liegt. Der Adressraum bleibt gleich groß.
Viele Tutorials und Bücher, die ich gelesen habe und die Verarbeitung von Binärdaten behandeln, lesen und schreiben direkt in und aus Strukturen aus oder in Dateien...
In vielen Tutorials und Büchern steht halt Müll drin.

-
Janjan schrieb:
Darauf musst du dank Standard in deinem Code nicht achten, darauf muss der Compiler für dich achten.

reinterpret_castheißt aber auch "ich weiß was ich hier tue, lass mich mal machen".Ishildur schrieb:
@Janjan
Puuhhhh.... Dank dir kann ich wieder ruhig schlafen
Nur weil er sagt was du hören willst, hat er noch lange nicht recht.
