Nun, grundsätzlich funktioniert das obige beispiel.
Jedoch nicht ganz. Weil offenbar überschneiden sich die beiden
Speicherbereiche. Wenn ich ein member am Anfang von filehead schreibe,
dann überschreibt es einige Variablen am Ende von infohead.
Offenbar liefert mir sizeof einen zu geringen Wert.
Habe es dann versucht mit der packed definition hinzukriegen.
1
__attribute__((__packed__))
Leider ohne Erfolg.
Ich verwende den arm-gcc
Hat jemand eine Idee, wie ich mit sizeof genügend Bytes geliefert
bekomme, damit sich die Bereiche nicht überschneiden?
Kaj G. schrieb:> Warum beziehst du das nicht direkt aufs struct?> infohead = malloc(sizeof(struct bmp_info_header));> filehead = malloc(sizeof(struct bmp_file_header));> Damit ist viel klarer und ersichtlicher, was du eigentlich willst.
Finde ich nun gerade nicht. infohead ist ein Zeiger auf irgendwas. Was
dieses irgendwas ist, sollte mich an dieser Stelle nicht interessieren.
Wichtig ist an der Stelle nur, dass man genau soviel Speicher allokiert,
wie für das, worauf infohead zeigt, benötigt wird, unabhängig davon, was
das nun genau ist. Und sizeof *infoead drückt exakt das aus.
Rolf M. schrieb:> infohead ist ein Zeiger auf irgendwas.
Richtig. Zu diesem Zeitpunkt ist es ein Zeiger der auf irgendwas im
irgendwo zeigt. Und dieses irgendwas im irgendwo wird als struct
bmp_info_header interpretiert.
Rolf M. schrieb:> Wichtig ist an der Stelle nur, dass man genau soviel Speicher allokiert,> wie für das, worauf infohead zeigt, benötigt wird,
infohaed zeigt zu diesem Zeitpunkt aber auf nichts, bzw. auf irgendwas.
Die bessere Formulierung waere also:
Wichtig ist an der Stelle nur, dass genau soviel Speicher allokiert
wird, wie fuer das Objekt, auf das infohead zeigen soll, benoetigt
wird.
Ich finde deine Einstellung etwas komisch. Legst Du auch erst einen
int-Pointer an, und wendest darauf sizeof an, oder wendest du sizeof
direkt auf int an?
1
int*ptr;
2
ptr=malloc(sizeof(*ptr));
3
4
ptr=malloc(sizeof(int));
Mag geschmackssache sein. Soll also jeder machen, wie er mag. :)
Edit:
Muesste sizeof(*ptr) nicht sogar undefined behavior sein? Es wird
immerhin ein nicht initialisierter Pointer dereferenziert.
Kaj G. schrieb:> Rolf M. schrieb:>> Wichtig ist an der Stelle nur, dass man genau soviel Speicher allokiert,>> wie für das, worauf infohead zeigt, benötigt wird,> infohaed zeigt zu diesem Zeitpunkt aber auf nichts, bzw. auf irgendwas.> Die bessere Formulierung waere also:> Wichtig ist an der Stelle nur, dass genau soviel Speicher allokiert> wird, wie fuer das Objekt, auf das infohead zeigen soll, benoetigt> wird.
Ja, richtig. Ich denke, es ist klar, dass das so gemeint ist.
> Ich finde deine Einstellung etwas komisch. Legst Du auch erst einen> int-Pointer an, und wendest darauf sizeof an, oder wendest du sizeof> direkt auf int an?> int *ptr;> ptr = malloc(sizeof(*ptr));>> ptr = malloc(sizeof(int));>> Mag geschmackssache sein. Soll also jeder machen, wie er mag. :)
Ich lege selten einzelne dynamisch allokierte ints an, aber ja, ich
schreibe bei malloc praktisch immer sizeof *ptr. Warum auch nicht? Wenn
das mal statt eines int ein long werden muss, kann ich nicht vergessen,
das beim malloc auch anzupassen - es passt sich von selber an den Typ
der Variable an. Das ist für mich der Hauptvorteil daran. Warum soll ich
auch den Typ nochmal explizit wiederholen, wo doch der Compiler genau
weiß, von welchem Typ der Zeiger ist?
> Edit:> Muesste sizeof(*ptr) nicht sogar undefined behavior sein? Es wird> immerhin ein nicht initialisierter Pointer dereferenziert.
Nein, sizeof ist in ISO C explizt davon ausgenommen, da es sich nicht
auf den Wert, sondern ausschließlich auf den Typ des übergebenen Objekts
bezieht. Der Operand, also hier das *ptr wird nicht evaluiert, und damit
findet keine tatsächliche Dereferenzierung statt.
Die Größe einer Struktur im physikalischen Ram und der von sizeof
geliefert Wert muss nicht immer identisch sein.
Sizeof liefert die definierte und nicht die physikalische Größe der
Struktur.
Ob das passt hängt davon ab wie der Compiler Konfiguriert und die
Struktur angelegt ist.
Eine Beispiel dazu:
typedef struct TEST
{
U8 Byte1;
U32 word1;
}
Steht der Kompiler auf Ramoptimierung:
Größe im Ram : 5 Byte
Größe Sizeof : 5 Byte
Steht der Kompiler auf Speedoptimierung:
Größe im Ram : 8 Byte
Größe Sizeof : 5 Byte
Warum ?
Recht einfach, der Compiler ergänzt die Struktur in dieser Art:
typedef struct TEST
{
U8 Byte1;
U8 Hole1;
U8 Hole2;
U8 Hole3;
U32 word1;
}
Das wird gemacht damit der nächste U32 Byte Zugriff auf einer passende
Grenze beginnt, und damit der Wert direkt ohne schieben ins Register
passt.
Man kann die Struktur aber recht einfach so anlegen das hier keine
Differenzen auftreten.
Indem man die Variablen nach ihrer Größe sortiert in der Stuktur anlegt.
Beispiel:
typedef struct TEST
{
U32 word1;
U16 int1;
U16 int2;
U8 Byte1;
U8 Byte2;
}
Kein Element der Struktur muss mit Holes auf eine zur Größe passenden
Adressgrenze geschoben werden.
So passen die physikalische Größe und der Wert aus Sizeof immer
zusammen.
Eine andere Frage.
Warum MALLOC ?
Eine dynamische Ramzuweisung hat immer das Potential zu fehlerhaften,
teilweise nicht reproduzierbaren und unerklärbarem Verhalten der
Software.
Warum ?
Recht einfach, zur Laufzeit kann es so jederzeit vorkommen das nicht
ausreichen Ram zur Verfügung steht um gerade die nächste MALLOC
ausführen zu können. Nach jedem Reset kann das aber an einer anderen
Stelle passieren, ganz besonders wenn da auch noch Interrupt im Spiel
sind.
Das zu debuggen ist der Horror
Besser ist es jeder Stuktur und Variablen zur Compilerzeiot eine feste
Adresse zuzuordnen. Dadurch steht zur Compilezeit schon fest ob
ausreichend Ram zur Verfügung steht.
Wenn das schon fehlschlägt kann eine dynamische Verwaltung nichts
retten. höchstens zeitweise überdecken.
Und gerade dann wenn man es nicht brauchen kann schlägt das dann doch
zu.
Auf Grund dieses nicht vorhersehbaren Verhaltens wird MALLOC in
sicherheitskritischen Anwendungen, wie zb Automotiv, nicht verwendet.
Ralph schrieb:> Sizeof liefert die definierte und nicht die physikalische Größe der> Struktur.
Leider genau falsch, sizeof liefert eben doch die physikalische Größe im
RAM - probier's mit deinem Beispiel aus! Das muss auch so sein, denn
sonst würde man ja z.B. bei malloc(sizeof(struct TEST)) zu wenig
Speicher anfordern. Die Padding-Bytes werden immer mitgezählt.
Ralph schrieb:> Warum MALLOC ?Ralph schrieb:> Besser ist es jeder Stuktur und Variablen zur Compilerzeiot eine feste> Adresse zuzuordnen.
Tja, das geht nicht immer. Bei PC-Anwendungen hat man oft dynamische
Datenstrukturen, deren Größe sich erst zur Laufzeit ergibt. Wenn man
immer das theoretische Maximum von allem allokiert, fordert man eine
Menge Speicher an und braucht ihn vielleicht gar nicht. Bei
eingebetteten Systemen lässt sich aber oft vorhersehen, wie viel man
braucht, und kann es statisch anlegen.
Holger K. schrieb:>> struct bmp_file_header> {> uint8_t bfType1;> uint8_t bfType2;> unsigned long bfSize;
Besser: uint32_t, denn da stehen immer 32 Bit. Und dem Leser wird es
auch klarer; C99 ist's eh schon.
> unsigned long bfReserverd;> unsigned long bfOffset;> };>> [...]>> Habe es dann versucht mit der packed definition hinzukriegen.
Auch wenn woanders noch ein Fehler war, ist __packed__ dennoch richtig.
Es gibt zwar Plattformen, die bei diesen Structs weder Paddings
innerhalb noch am Ende einfügen, aber wenn das nicht so ist suchst du
dir den Wolf. Und sizeof beim Kopieren hat evtl. nicht die Größe eines
Headers, die hier 2 mod 4 ist. Ergo: __packed__.