Alignment dword, word



  • Hallo,

    /*********************************************************************
     *
     * Purpose: Find out the size of different data types and structs
     *
     ********************************************************************/
    void special_case(void);
    #include <stdio.h>
    int main()
    {
            special_case();
    	return 0;
    }
    void special_case(void)
    {
    	struct
    	{
    		char a;
    		int b;
    	}d;
    	struct
    	{
    		char a;
    		short int b;
    	}e;
    	struct
    	{
    		char a;
    		int b;
    		char c;
    	}f;
    	struct
    	{
    		char a;
    		short int b;
    		char c;
    	}g;
    	printf(" d is   %2d bytes \n", sizeof(d));
    	printf(" d.a is %2d bytes \n", sizeof(d.a));
    	printf(" d.b is %2d bytes \n", sizeof(d.b));
    //	printf(" d.c is %2d bytes \n", sizeof(d.c));
    	printf("\n");
    	printf(" e is   %2d bytes \n", sizeof(e));
    	printf(" e.a is %2d bytes \n", sizeof(e.a));
    	printf(" e.b is %2d bytes \n", sizeof(e.b));
    //	printf(" e.c is %2d bytes \n", sizeof(e.c));
    	printf("\n");
    	printf(" f is   %2d bytes \n", sizeof(f));
    	printf(" f.a is %2d bytes \n", sizeof(f.a));
    	printf(" f.b is %2d bytes \n", sizeof(f.b));
    	printf(" f.c is %2d bytes \n", sizeof(f.c));
    	printf("\n");
    	printf(" g is   %2d bytes \n", sizeof(g));
    	printf(" g.a is %2d bytes \n", sizeof(g.a));
    	printf(" g.b is %2d bytes \n", sizeof(g.b));
    	printf(" g.c is %2d bytes \n", sizeof(g.c));
    	return;
    }
    
    /* Output:
     d is    8 bytes 
     d.a is  1 bytes 
     d.b is  4 bytes 
    
     e is    4 bytes 
     e.a is  1 bytes 
     e.b is  2 bytes
    
     f is   12 bytes 
     f.a is  1 bytes 
     f.b is  4 bytes 
     f.c is  1 bytes 
    
     g is    6 bytes 
     g.a is  1 bytes 
     g.b is  2 bytes 
     g.c is  1 bytes 
    */
    

    struct d und e verstehe ich ja noch; aber wieso ist f und g nicht logischerweise 9 resp 5 bytes? Compiliert habe ich mit gcc auf einem x86.
    Im Wiki lese ich http://de.wikipedia.org/wiki/X86-Prozessor

    Die x86-Architektur verwendet einen CISC-Befehlssatz mit variabler Instruktionslänge. Speicherzugriffe in Wortgröße sind auch auf nicht Wort-ausgerichtete Speicheradressen erlaubt. Wörter werden in Little-Endian-Richtung gespeichert. [...]

    Kann das jemand erklären oder habe ich einen Denkfehler??



  • Guckst Du http://www.c-plusplus.net/forum/viewtopic-var-p-is-1182288.html
    und http://de.wikipedia.org/wiki/Speicherausrichtung und liest Du Compiler doku (zwar jetzt MS, nachm GCC such' ich nicht), dann wird alles klar. Der Begriff für das Phänomen lautet Padding Bytes.



  • am besten sortierts mal die members und zwar so...

    void special_case(void);
    #include <stdio.h>
    int main()
    {
            special_case();
        return 0;
    }
    void special_case(void)
    {
        struct
        {
            int b;
            char a;
        }d;
        struct
        {
        	short int b;
            char a;
        }e;
        struct
        {
        	int b;
            char a;
            char c;
        }f;
        struct
        {
        	short int b;
            char a;
            char c;
        }g;
        printf(" d is   %2d bytes \n", sizeof(d));
        printf(" d.a is %2d bytes \n", sizeof(d.a));
        printf(" d.b is %2d bytes \n", sizeof(d.b));
    //    printf(" d.c is %2d bytes \n", sizeof(d.c));
        printf("\n");
        printf(" e is   %2d bytes \n", sizeof(e));
        printf(" e.a is %2d bytes \n", sizeof(e.a));
        printf(" e.b is %2d bytes \n", sizeof(e.b));
    //    printf(" e.c is %2d bytes \n", sizeof(e.c));
        printf("\n");
        printf(" f is   %2d bytes \n", sizeof(f));
        printf(" f.a is %2d bytes \n", sizeof(f.a));
        printf(" f.b is %2d bytes \n", sizeof(f.b));
        printf(" f.c is %2d bytes \n", sizeof(f.c));
        printf("\n");
        printf(" g is   %2d bytes \n", sizeof(g));
        printf(" g.a is %2d bytes \n", sizeof(g.a));
        printf(" g.b is %2d bytes \n", sizeof(g.b));
        printf(" g.c is %2d bytes \n", sizeof(g.c));
        return;
    }
    

    dann kommt da sowas...

    d is    8 bytes 
     d.a is  1 bytes 
     d.b is  4 bytes 
    
     e is    4 bytes 
     e.a is  1 bytes 
     e.b is  2 bytes 
    
     f is    8 bytes 
     f.a is  1 bytes 
     f.b is  4 bytes 
     f.c is  1 bytes 
    
     g is    4 bytes 
     g.a is  1 bytes 
     g.b is  2 bytes 
     g.c is  1 bytes
    

  • Mod

    Erlaubt heißt nicht unbedingt, dass man das auch machen muss. es steht dem Compiler frei, die Datenstrukturen mit Paddingbytes zu versehen wenn er glaubt, dass dies effizienter ist (was es auch ist). Die meisten Compiler haben auch spezielle Schalter mit denen man dieses Verhalten abstellen kann.

    edit: Oh. Bin viel zu langsam beim antworten gewesen...



  • .. ist die Lösung.

    Besten Dank für die Hinweise und Tipps!

    Mit

    #pragma pack(push)  /* push current alignment to stack */
    #pragma pack(1)     /* set alignment to 1 byte boundary */
        struct
        [...]
    #pragma pack(pop)   /* restore original alignment from stack */
    

    ist das Prob gelöst.


  • Mod

    Was heißt Problem? Eigentlich ist das eine gute Sache, solange dir nicht gerade der Speicher knapp ist...



  • SeppJ schrieb:

    Was heißt Problem? Eigentlich ist das eine gute Sache, solange dir nicht gerade der Speicher knapp ist...

    Ich konstruiere mal ein Beispiel:
    Wenn ich einen Absturz ohne jegliche Debugginginformationen untersuchen muss - etwa ein übergelaufener Index und ich 100% nur auf einen Hex Dump angewiesen bin, erleichtert es die Analyse enorm, wenn man Struct-Elemente abzählen kann und damit die Bytes weiss, um anschliessend den Inhalt des betroffenen Feldes zu untersuchen....
    Im vorliegenden Fall ist mir das Phänomen der Paddingbytes eher zufällig aufgefallen.
    Nochmals besten Dank!



  • SaHel schrieb:

    Im vorliegenden Fall ist mir das Phänomen der Paddingbytes eher zufällig aufgefallen.
    Nochmals besten Dank!

    Das wird Dir noch häufiger vorkommen, ist ein schöner Fallstrick auch bei DLLs, die einander Structs zuschieben sollen, zuletzt war's irgendwas mit Delphi. Aber auch binary in files abgelegte structs zählen dazu.

    Zur Abrundung: #pragma pack ist ein zweischneidiges Schwert, das ist absolutely "compiler defined" und damit evtl. inportabler code. Pass auf, daß Dir das nicht irgendwann auf den Kopf fällt.

    So much for fun 😃

    Edit: Jaja, das Wichtigste beim Tippeln vergessen 😉


Anmelden zum Antworten