Hallo erst einmal zusammen. Ich habe ein kleines C-Problem mit einem
struct. Schon mal im Voraus, ich benutze Dev C++ 4.9.9.2.
Jetzt zum Programm. Aus der folgenden Datei soll der markierte Teil in
ein struct eingelesen werden.
test.dat
00 00 |0A 00 00 00 FF 00 00 00 08 FF 00 00 00 00| 00 00
Wenn ich jetzt im struct unsigned char map_height; verwende wird der
folgende Teil korrekt eingelesen:
00 00 |0A 00 00 00 FF 00 00 00 08 FF| 00 00 00 00 00 00
Wenn ich jetzt aber unsigned int map_height; verwende erhalte ich als
Ausgabe für map_height keine 255. Ich habe mehr oder weniger das Gefühl,
dass beim Marker1 der ein char ist 4 Byte statt einem eingelesen werden
und darum alles um 3 Byte verrutscht. Wenn ich die test.dat wie folgt
verändere erhalte ich für map_height eine 255!!
00 00 0A 00 00 00 FF 00 00 00 08 FF 00 00 FF 00 00 00
Können mir der C-Experten evtl. sagen, was ich falsch mache oder ob es
ein Bug oder Einstellungsfehler ist??
ich schrieb:
> Können mir der C-Experten evtl. sagen, was ich falsch mache oder ob es> ein Bug oder Einstellungsfehler ist??
Die Strukturen legt der Compiler 4 Byte aligned an. Du must dem Compiler
über eine Kommandozeilen-Option oder evtl. als Attribut der Struktur
mitteilen, dass er die Strukturen packen soll (packed). Dann legt er sie
exakt so an, wie du möchtest.
Warum er allerdings bei deiner ersten Variante die beiden chars nicht 4
Byte aligned, weiß ich gerade auch nicht. Evtl. weil sie am Ende stehen.
ich schrieb:
> Wenn ich jetzt aber unsigned int map_height; verwende erhalte ich als> Ausgabe für map_height keine 255. Ich habe mehr oder weniger das Gefühl,> dass beim Marker1 der ein char ist 4 Byte statt einem eingelesen werden> und darum alles um 3 Byte verrutscht.
Nicht ganz, aber fast.
> Können mir der C-Experten evtl. sagen, was ich falsch mache oder ob es> ein Bug oder Einstellungsfehler ist??
Du beachtest nicht die Probleme, die entstehen, wenn man Binärdaten auf
einen Rutsch einfach in eine Struktur liest. In deinem Fall lautet das
Stichwort "alignment". Je nach Architektur ist ein Zugriff auf eine
Variable mit falschem Alignment langsam oder gar nicht durchführbar.
Deshalb werden in Strukturen ggf. ungenutzte Bytes eingefügt, um das
korrekte Alignment aller Elemente zu gewährleisten. Bei dir wird der
Compiler daher nach Marker1 drei leer-Bytes eingefügt haben, damit
map_height wieder bei einem Vielfachen von 4 beginnt (da bei dem von dir
verwendeten Compiler int 4 Bytes groß ist).
900ss D. schrieb:
> Die Strukturen legt der Compiler 4 Byte aligned an. Du must dem Compiler> über eine Kommandozeilen-Option oder evtl. als Attribut der Struktur> mitteilen, dass er die Strukturen packen soll (packed). Dann legt er sie> exakt so an, wie du möchtest.
Ist allerdings recht unportabel. Aber das ist das Einlesen von
Binärdaten ohne weitere Vorkehrungen ja sowieso.
> Warum er allerdings bei deiner ersten Variante die beiden chars nicht 4> Byte aligned, weiß ich gerade auch nicht.
Warum sollte er das tun?
Weiters wirst du genau dann wieder stolpern, wenn die Endianness nicht
mehr stimmt. Dann nämlich bekommst du Probleme, wenn du Multibytes
(16-Bit-Worte, 32-Bit-Integer usw.) direkt und Binär aus der Datei
holst.
Sven P. schrieb:
> wenn du Multibytes> (16-Bit-Worte, 32-Bit-Integer usw.) direkt und Binär aus der Datei> holst.
Und was macht er gerade? Er öffnet die Datei mit "rb" (read binary).
Dann bekommst du Daten direkt als binary. Und ob du 1 oder 3 "int"
hintereinander holst ist dann egal.
Ja, das ist egal. Aber wie die einzelnen ints kommen, das ist nicht
egal. Wenn in der Datei zuerst das höchstwertige Byte steht, du aber auf
einer Little-Endian-Maschine arbeitest, steht nachher ein falscher
Zahlenwert im int. In dem Fall würde fread zuerst ein Byte lesen
(höchstwertiges), dann an die erste Speicherstelle schreiben
(niederwertigstes Byte der vier Bytes des Integers) usw.
Kann mir noch jemand einen Tipp geben, nach was ich genau suchen muss?
Stichwort:
- endianness - noch nie gehört
- packed - schon mal gesehen, da muss ich mal suchen...
Oder mit anderen Worten, wie schwer ist eine Anpassung, so dass das
passiert was ich möchte?
Rolf Magnus schrieb:
> Am besten informierst du dich, was "endianness" ist und antwortest> danach nochmal.
Warum?
Der TO macht das schon, also multibyte (int) einlesen im binary Format.
Und es funktioniert. Seine Daten liegen für eine x86 Architektur (nehme
ich jetzt mal an) richtig in der Datei. Ob durch Zufall oder nicht...
keine Ahnung. Er wird nicht mehr darüber stolpern in seinem jetzigen
Projekt.
Deshalb schrieb ich: er macht genau das (richtig).
Einfach anzunehmen, dass die Endianness nicht mehr stimmt... warum?
Sollte sie sich in seinem Projekt einfach ändern?
"ich" schrieb:
> Ich habe es mal so versucht. Passt jetzt. Hoffe ich zu mindestens.
Prima. Jetzt sollte es funktionieren.
Da du nicht weißt, was endianness ist, informiere dich wie A.K. schrieb
im Wikipedia. Ist schon wichtig zu wissen. Aber für deinen jetzigen Fall
ist es richtig.
900ss D. schrieb:
> Der TO macht das schon, also multibyte (int) einlesen im binary Format.> Und es funktioniert. Seine Daten liegen für eine x86 Architektur (nehme> ich jetzt mal an) richtig in der Datei. Ob durch Zufall oder nicht...> keine Ahnung. Er wird nicht mehr darüber stolpern in seinem jetzigen> Projekt.>> Deshalb schrieb ich: er macht genau das (richtig).>> Einfach anzunehmen, dass die Endianness nicht mehr stimmt... warum?> Sollte sie sich in seinem Projekt einfach ändern?
Vielleicht soll sein Programm ja portabel sein, oder die Daten stammen
von einem anderen Rechner?
Sven P. schrieb:
> Vielleicht....
Von "Vielleicht" und anderen fiktiven Fällen stand nirgends etwas. In
seinem jetzigen Fall ist alles gut so. Und wenn du alle möglichen
anderen Fälle hier aufführen willst, dann wird dein Posting ziemlich
lang. ;-) Was muß er z.B. machen wenn er eine CPU nutzt, die nicht
einzelne Bytes adressieren kann geschweige denn Wort-Zugriffe auf nicht
geraden Adressen u.s.w.
900ss D. schrieb:
> Rolf Magnus schrieb:>> Am besten informierst du dich, was "endianness" ist und antwortest>> danach nochmal.>> Warum?
Weil Sven P. schrieb:
> Weiters wirst du genau dann wieder stolpern, wenn die Endianness> nicht mehr stimmt.
und deine Antwort darauf war:
> Er öffnet die Datei mit "rb" (read binary).Dann bekommst du Daten direkt> als binary. Und ob du 1 oder 3 "int" hintereinander holst ist dann> egal.
Da deine Antwort überhaupt nichts mit Endianness zu tun hat, war ich
davon ausgegangen, daß du das Posting, auf das du geantwortet hast,
nicht verstanden hast.
> Der TO macht das schon, also multibyte (int) einlesen im binary Format.> Und es funktioniert. Seine Daten liegen für eine x86 Architektur (nehme> ich jetzt mal an) richtig in der Datei. Ob durch Zufall oder nicht...> keine Ahnung. Er wird nicht mehr darüber stolpern in seinem jetzigen> Projekt.
Solange die Endiannes des System, das die Datei mal geschrieben hat,
immer gleich der des Systems, das sie liest, bleibt.
> Deshalb schrieb ich: er macht genau das (richtig).>> Einfach anzunehmen, dass die Endianness nicht mehr stimmt... warum?> Sollte sie sich in seinem Projekt einfach ändern?
Es ging nicht darum, daß die Endianness sich auf jeden Fall ändert,
sondern daß, falls sich die Endianness ändert, der Code damit ein
Problem hat.
Wenn man sich nicht mal bewußt ist, welche potenziellen
Portabilitäts-Probleme man sich mit dem Einlesen von Binärdaten
einhandeln kann, hat man keine Grundlage, um zu entscheiden, ob man
damit leben kann oder nicht. Deshalb finde ich es besser, das zu
erwähnen statt zu verschweigen.
Nicht alle Projekte sind auf ein einziges System beschränkt, und nicht
jeder kann es sich leisten, unter der Annahme zu programmieren, daß der
Code niemals auf irgendein anderes System portiert werden könnte.
> Von "Vielleicht" und anderen fiktiven Fällen stand nirgends etwas. In> seinem jetzigen Fall ist alles gut so.
Du kennst seinen "jetzigen Fall" doch überhaupt nicht. Also ist auch
nur "vielleicht" alles gut.
> Was muß er z.B. machen wenn er eine CPU nutzt, die nicht einzelne Bytes> adressieren kann geschweige denn Wort-Zugriffe auf nicht geraden> Adressen u.s.w.
Ersteres ist heutzutage recht unwahrscheinlich, und wenn er so eine CPU
hätte, wüßte er es auch. Und zweiteres habe ich ja bereits erwähnt.
Stichwort "alignment".
@ Rolf Markus: Da diese Diskussion dem TO nicht mehr hilft, lass ich es
mal gut sein bis auf die Ausnahme unten, die zeugt von echtem Unwissen
deinerseits.
Rolf Magnus schrieb:
>> Was muß er z.B. machen wenn er eine CPU nutzt, die nicht einzelne Bytes>> adressieren kann geschweige denn Wort-Zugriffe auf nicht geraden>> Adressen u.s.w.>> Ersteres ist heutzutage recht unwahrscheinlich,
Ach ja?
900ss D. schrieb:
>> Ersteres ist heutzutage recht unwahrscheinlich,>> Ach ja?
Ja, ich halte es für unwahrscheinlich, daß er so eine CPU hat, es nicht
weiß und damit Dateien lesen und/oder schreiben will. Du nicht?
Hallo,
habe auch Dev-C++ und ebenfalls das selbe Problem mit dem Allignment.
Ich benutze ebenso das Attribute packed, jedoch wird es vom Compiler
ignoriert und er macht es wieder so wie er will (mit 2 byte, warum auch
immer?!).
Weiss jemand wie man den Compiler dazu zwingen kann das alignment zu
akzeptieren? Vielen Dank!
Sitz schon eine Woche an diesem Problem und komme kein Stueck voran.
Vielleicht muss ich den compiler wechseln?!
Gruss daniel
Hallo,
tja man muss halt erst ein Forum zumuellen mit sinnlosen Posts.
Das Problem liegt daran das ST_TP_ZWEIG ebenso ein packed enthalten
muss.
ausserdem ist "pack(1)" einfach falsch an der Stelle, sowas existiert
nur als #pragma pack(1). Es muss also __attribute__((_packed_)) sein.
Vielleichts nuetzts mal jemanden und er vergeudet nicht eine woche mit
augenaufreibenden Stunden.
Gruss
daniel