Speicherinterne Darstellung einer Struktur



  • Vielen Dank schon mal!

    Padding bekomme ich meines wissens nach nur bei 2Byte-Integers oder ähnlichem.
    Solange ich nur unsigned long und floats habe dürfte das nicht auftreten.

    Zumindest beim Pentium 4 müsste das so gewesen sein.



  • Du hast weder eine Garantie, wie lang deine Datentypen sind, noch wie diese im Speicher liegen.

    Die einzige Garantie ist, dass Du ein struct in sein erstes Element casten kannst.

    Alles andere, was Du da z.B. gemacht hast, bezieht sich auf bestimmte Compiler, Platformen, etc..



  • Hmm...
    Das klingt jetzt nicht so gut.

    Jetzt habe ich zwei konträre Meinungen und kann leider keine Entscheidung fällen.

    Solange ich mich auf Systemen mit x86-Prozessor bewege, bin ich zumindest mit dem Little-Endian-System fein raus. Die Gleitkommadarstellung ist meines Wissens nach auf allen x86-Systemen ebenfalls korrekt.

    Soviel habe ich herausfinden können.
    Bleibt nur noch die Frage, wie sich der Rechner dann eine Struktur bastelt.

    Kann mir noch jemand helfen?

    Gruß,
    chris_f



  • Wie schon gesagt kann sich das der Compiler so zusammen basteln wie er will (mit der Ausname von dem was 7H3 N4C3R sagte)



  • Das ist sehr Schade. Hatte gehofft, das die Zuordnung eindeutig ist.

    Danke euch allen.

    Gruß,
    chris_f



  • Die Zuordnung wird schon eindeutiger, wenn Du ein unsigned char array verwendest, welches in einem Stück deklariert und initialisiert wird. Und dann die richtigen Werte zuweisen.

    Die Richtung ist aber immer unbestimmt.

    Blackbird



  • Um Dir die Hoffnung nicht ganz zu nehmen: Irgendwie muss es ja im Speicher dargestellt werden. Die Länge eines unsigned long kannst Du mit dem sizeof Operator abfragen. Auf einer typischen x86 Plattform sollten das 64 Bit sein. Und typischer Weise auch Little Endian. Mit ein Wenig Glück werden floats auch in IEEE-Darstellung abgelegt. Ein Float sollte 32 Bit haben. Und Padding erfolgt normalerweise auch nur auf die nächste 32-Bit oder 64-Bit Adresse (ist meist ein Compiler-Setting).

    Die Sache ist halt, dass Dir niemand das garantiert. Ein Wechsel des Compilers kann schon dafür sorgen, dass das nicht mehr funktioniert. Wenn es Dir reicht, dass es für deinen Compiler in der jetzigen Version auf deiner derzeitigen Plattform funktioniert, ist das doch schon gut. Portabel in irgendeiner Art und Weise ist es aber nicht.

    Little oder Big Endian kannst Du auch zur Laufzeit bestimmen (vorausgesetzt, uint ist größer als uchar):

    unsigned int i = 1;
      unsigned char* c = reinterpret_cast<unsigned char*>( &i);
      if( *c != 0) {
        // Little Endian
      }
      else {
        // Big Endian
      }
    

    Ich hoffe mal, ich habe Little und Big jetzt nicht verdreht 🙂 Ansonsten, tausch es einfach.



  • Und um dir noch ein bißchen mehr Hoffnung zu machen: In der Praxis kannst du, zumindest auf den üblichen Plattformen und Compilern, von folgendem ausgehen:

    - Die Felder werden in der Reihenfolge der Deklaration abgelegt.
    - Der Compiler fügt (wenn man es nicht anders einstellt) Padding-Bytes ein, soweit notwendig.
    - Die Elemente eines Arrays werden in aufsteigender Reihenfolge abgelegt. Das ist definitiv garantiert. Zudem ist adressof(Element 1) = addressof(Element 0) + sizeof(Elementtyp), usw.
    - Das Alignment einer Struktur richtet sich nach dem Alignment ihres größten Felds; wenn z.B. das größte Feld ein 64bit integer ist, dann hat auch die Struktur ein Alignment von 8 Byte.
    - Daher kann es sein, daß am Ende einer Struktur noch Padding-Bytes eingefügt werden, damit direkt danach eine weiter solche Struktur mit richtigem Alignment liegen kann (ist für Arrays wichtig).

    Wieviel davon vom Standard garantiert ist, weiß ich nicht. Aber in der Praxis wäre C/C++ als systemnahe Sprache unbrauchbar, wenn diese Garantien nicht zumindest De-Facto-Garantien wären.

    Gruß
    Rolf



  • Wenn du es tatsächlich in einem Programm verwenden willst (fragt sich zwar wieso, aber du wirst deine Gründe haben), dann mach doch folgendes:
    Überprüfe, ob deine Annahme stimmt und die zahlen im Speicher so abgelegt werden wie du denkst. Bastle dir einen entsprechenden Struct, bei dem die byteweise Darstellung eindeutig ist. (z.B. der unsigned long als 1001 1000 0010 1101)
    Dann lass dir einen Pointer auf den Anfang des structes zurückgeben sowie ein sizeof(mystruct). Wenn das sizeof stimmt musst du nur noch den pointer auf einen unsigned char pointer umcasten und byte für byte durchgehen und nachschauen ob du die bytes vorfindest die du erwartest. Falls ja -> Glückwunsch, falls nicht -> Programm beenden. Die Methode kann dir sogar noch mehr verraten. Du kannst dir ja vorher einige mögliche Verhaltensweisen des Compilers/der Plattform denken und dich darauf einrichten, dass sie al vorkommen können (Big Endian/Little Endian, padding auf 32 bit oder 64 bit etc. Wenn dein sizeof(mystruct) dir jetzt 128 bit liefert weißt du z.B. dass du ein padding auf 64 bit hast. Und wenn die einzelnen bytes deines ulong "falschrum" im Speicher liegen hast du ein big Endian System und kannst dich drauf einrichten...
    Ist zwar alles etwas umständlich, aber wer so tief in die Trickkiste greifen muss dass er sich um die Speicherbelegung sorgen macht, der wird sich von solchen banalitäten nicht abschrecken lassen 😉



  • Das hört sich ja alles schon viel besser an!

    Ich werde das ganz einfach mal ausprobieren. Die Anwendung um die es hier geht ist sehr spezifisch und muß daher nur in einer Umgebung funktionieren. Wenn es doch nicht klappt, müsste ich mir mit der von pumuckl vorgeschlagenen Methode behelfen können. Auf alle Fälle werde ich das ganze so aufbauen, dass ich das noch nachträglich einbauen kann.

    Vielen Dank euch allen!

    Gruß,
    chris_f


Anmelden zum Antworten