Wieso ist eine Struct größer als ihre definitierte Größe?

  • Hallo zusammen,
    beim Arbeiten mit structs ist mir etwas aufgefallen, was ich so nicht erwartet hätte:
    Wenn man eine Struct mit

    [autoit]

    $struct1=dllstructcreate(byte[8])

    [/autoit]

    erstellt, dann hat diese Struct eine Größe von 8 Byte, soweit klar!
    Aber!
    Erstellt man nun eine struct, welche genau "über" der andern struct liegt (bzw an deren Position im Speicher) dann sieht man, daß die Elemente in einer Struct immer so groß sind (Bitanzahl) wie das größte Einzelelement.
    Bsp:

    [autoit]

    $struct1=dllstructcreate("byte[12]") ;12 Byte
    $struct2=DllStructCreate("byte;int;byte",dllstructgetptr($struct1)) ;6 Byte an der Position von struct1

    [/autoit][autoit][/autoit][autoit]

    ;schreiben in die struct2, real geschrieben wird an position der struct1
    dllstructsetdata($struct2,1,0xAB) ;1 Byte
    dllstructsetdata($struct2,2,0xAABBCCDD) ;4 Byte
    dllstructsetdata($struct2,3,0xBA) ;1 Byte

    [/autoit][autoit][/autoit][autoit]

    ;nun sollte man erwarten, daß (little endian) der Inhalt der struct1 "ABDDCCBBAABA" ist...byte&int&byte=6 byte

    [/autoit][autoit][/autoit][autoit]

    ;lesen der Daten von struct1
    $wert=dllstructgetdata($struct1,1) ;12 byte werden gelesen, aber der Inhalt ist AB000000DDCCBBAABA000000 also nicht ABDDCCBBAABA
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $wert = ' & $wert & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

    [/autoit][autoit][/autoit][autoit]

    ;sieht man auch an den pointern
    $p1=dllstructgetptr($struct2,1)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $p1 = ' & $p1 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $p2=dllstructgetptr($struct2,2)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $p2 = ' & $p2 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $p3=dllstructgetptr($struct2,3)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $p3 = ' & $p3 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    ;der abstand der pointer beträgt 4 byte

    [/autoit][autoit][/autoit][autoit][/autoit]

    das heißt, daß obwohl bei der Definition der struct2 für das erste Element als Größe 1 Byte angegeben wird, ist der tatsächliche "Speicherverbrauch" 4 Byte. Wieso das?
    Bei einer struct von "byte;int64;byte" ist die tatsächliche Größe nicht 1+8+1 bytes sondern 3*8 Bytes, gibts dafür einen Grund?

  • Also vorweg: ich habe von sowas generall keinen Schimmer, trotzdem muss ich wie immer meinen Senf dazu geben. Ich nehme als Beispiel mal eine Handelsübliche Festplatte. Wie du sicherlich weisst, ist so eine Festplatte in Sektoren unterteilt. Hat man nun zum Beispiel eine Sektorengröße von 32 Byte, und speichert eine 5 Byte Datei auf der Festplatte, so belegt diese winzige Datei trotzdem die vollen 32 Byte. Vielleicht ist es bei einer Struct so, dass das größte Element die "Sektorengröße" angibt. Nur so ein Gedanke, kenne mich da wie gesagt nicht so gut aus.

    • Offizieller Beitrag

    Hab das jetzt mal mit verschiedenen Datentypen getestet und komme leider auch zu dem niederschmetternden Ergebnis:
    Strukturgröße = Speicherbedarf größter Datentyp * Anzahl aller Strukturelemente inkl. Unterelemente

    Das haut natürlich ganz schön rein, wenn man ein 'double' mit 8 Byte dabei hat und sonst nur 'byte'.
    Warum das so ist - keinen Schimmer, aber es ist leider so.

    • Offizieller Beitrag

    Das haut natürlich ganz schön rein, wenn man ein 'double' mit 8 Byte dabei hat und sonst nur 'byte'.

    Man merkt, das BugFix noch an C64 Zeiten sich gerne zurückerinnert. 64 Kilobyte Ram. Wow, war das viel ;)
    Ich denke mit zwei bis vier Gigabyte pro PC sollte das kein größeres Problem mehr darstellen. Das haben sich sicherlich auch die AutoIt programmierer gedacht.
    Suchen sich das größte Struckt raus und multiplizieren es mit der Anzahl der Structs. (So geht man auf Nummer sicher.)

    Gruß
    Spider

  • Zitat

    Autsch
    da haben wir diesmal auch vergessen die Hilfe zu lesen.

    uuuuuuhhhhh....schande, am schlimmsten daran ist, daß ich mir letzte Woche noch beim durchsehen alter Assemblerprogramme Infos bzgl. des Alignments geholt habe...

    Zitat

    Man merkt, das BugFix noch an C64 Zeiten sich gerne zurückerinnert. 64 Kilobyte Ram. Wow, war das viel

    Es geht nicht primär um den Speicherverbrauch, sondern darum, daß man mit der "Überlagerung" mehrerer Structs in einem Speicherbereich sehr schnell und einfach (für AutoItverhältnisse) Daten ändern/bearbeiten kann.

    Zitat

    Suchen sich das größte Struckt raus und multiplizieren es mit der Anzahl der Structs. (So geht man auf Nummer sicher.)

    Verstehe ich ehrlich gesagt nur vor dem Hintergrund, daß man so keine Verweise auf die Größe der einzelnen Elemente zwischenspeichern muss. Somit haben die Pointer auf die einzelnen Elemente immer denselben Abstand => schnelleres "durchlaufen" bei großen Structs (Arrays), und das Schreiben von Daten in Prozessor-Register funktioniert ohne vorheriges "anpassen" (alignment).

    • Offizieller Beitrag

    Ja, für solche Speicherzugriffe auf Arrays (gleiche Länge der Elemente) gibt es Maschinenbefehle, die der Prozessor direkt ausführen kann und dann selbst Offsets berechnet und so. Sobald man mehr als ein Minimum an Speicher hat, lohnt sich das sicherlich :).

    Johannes

  • Zitat

    Sobald man mehr als ein Minimum an Speicher hat, lohnt sich das sicherlich

    touché :thumbup:

  • Zitat

    16. Align, align, align.
    It is really important to align both your code and data to get a good speed up. I generally align code on 4 byte boundaries. For data I align 2 byte data on 2 byte boundaries, 4 byte data on 4 byte boundaries, 8 byte data on 8 byte boundaries, 16 byte data on 16 byte boundaries. In general if you don't align your SSE or SSE2 data on a 16-byte boundary you will get an exception. You can align your data in VC++ if you have the processor pack. They added support for both static data and dynamic memory. For static data you use __declspec(align(4)) - alignes on a 4 byte boundary.


    Assembly Optimization Tips


    Gruß
    Greenhorn