Auf Struktur dynamisch zugreifen - Alignment problem?



  • Hallo,

    ich habe folgenden Code.

    in graphwin->Data sind 4 Strukturen vom gleichen Typ wie graphwin->Data.Bottom

    SIZE(graphwin->Data, graphwin->Data.Bottom) ergibt 4

    typedef struct WindowOpt_typ
        {
            DINT Value;
            BOOL In;
            BOOL Out;
            USINT State;
        }WindowOpt_typ;
    
        typedef struct WindowData_typ
        {
            WindowOpt_typ Left;
            WindowOpt_typ Top;
            WindowOpt_typ Right;
            WindowOpt_typ Bottom;
        }WindowData_typ;
    
        WindowOpt_typ *pwinopt;
    
        for(i=0; i<SIZE(graphwin->Data, graphwin->Data.Bottom); i++)
        {
            pwinopt = &graphwin->Data+i*sizeof(graphwin->Data.Bottom);
            pwinopt->State = 0;
            pwinopt->Value = 0;
            /*memset(&pwinopt->State, 0, sizeof(pwinopt->State));
            memset(&pwinopt->Value, 0, sizeof(pwinopt->Value));*/
        }
    

    Warum funktioniert das so nicht? Sollte das funktionieren? Oder kann es durch ein Alignment nicht funktionieren?



  • Beim rechnen mit Zeigern werden nicht Bytes addiert sondern die Elementegrösse.

    int n;
    char *pc = &(char)(n);
    int  *pi = &n;
    
    printf("char %p, %p\n", pc, pc+1); // ein Byte weiter
    printf(" int %p, %p\n", pi, pi+1); // vier Byte weiter ( bei sizeof(int) == 4)
    

    Darum solltest du deine Zeile 23 nochmal überdenken.



  • Anaconda55 schrieb:

    WindowOpt_typ *pwinopt;

    for(i=0; i<SIZE(graphwin->Data, graphwin->Data.Bottom); i++)
    {
    pwinopt = &graphwin->Data+i*sizeof(graphwin->Data.Bottom);
    pwinopt->State = 0;
    pwinopt->Value = 0;
    /memset(&pwinopt->State, 0, sizeof(pwinopt->State));
    memset(&pwinopt->Value, 0, sizeof(pwinopt->Value));
    /
    }
    [/cpp]

    Das ist absoluter Schrott.
    Speicherbereiche fordert man mit *alloc an und weißt sie dann üblicherweise einem Zeiger zu.

    WindowOpt_typ *pwinopt = malloc( sizeof(WindowOpt_typ) );
    WindowOpt_typ *pwinopt = malloc( sizeof *pwinopt );
    

    bzw. Platz für mehrere Elemente

    WindowOpt_typ *pwinopt = calloc( anzahl, sizeof *pwinopt );
    

    wobei calloc den Vorteil hat, dass der angeforderte Speicherbereich 0 initialisiert ist und man (so wie du) nicht noch selbst initialisieren muss und dabei Fehler macht.

    WindowOpt_typ *pwinopt = calloc( 1, sizeof *pwinopt );
    

    Sind alles absolute Grundlagen der C Programmierung.



  • Wutz schrieb:

    WindowOpt_typ *pwinopt = calloc( 1, *pwinopt );
    

    Sind alles absolute Grundlagen der C Programmierung.

    Ich muß zugeben, daß ich darauf nicht gekommen wäre. Muß am Fasching liegen.



  • @ DirkB: Danke! Das ist das Problem. Richtig.



  • Sag mal, Wutz, für jemanden mit deinem Kenntnisstand reißt du das Maul regelmäßig erstaunlich weit auf. Würde es dich umbringen, einen Post zu lesen und über seinen Inhalt nachzudenken, bevor du dessen Autor beschimpfst? Mit polemischer Kritik, die an der Sache völlig vorbei geht und deren fachlicher Inhalt selbst dann höchst fragwürdig wäre, wenn sie es nicht täte, lässt du dich selbst ziemlich lächerlich aussehen. Kleiner Tip:

    WindowOpt_typ winopt;
    

    fordert ganz ohne malloc einen Speicherbereich an und könnte durchaus als absolute Grundlage der C-Programmierung bezeichnet werden.

    Aber zurück zum eigentlichen Problem: Gibt es der Standard wirklich her, ein Struct gleichtypiger Member als Array zu behandeln? Im Grunde macht Anaconda55 ja in Folgendes:

    typedef union {
      WindowData_typ *wd;
      WindowOpt_typ *wo_array;
    } WindowData_punner;
    
    WindowData_punner punner;
    
    punner.wd = graphwin;
    
    for(i = 0; i < 4; ++i) {
      punner.wo_array[i].State = 0;
      punner.wo_array[i].Value = 0;
    }
    

    ...und ich bin mir gerade nicht sicher, dass diese Art des Type-Punnings definiertes Verhalten ist. In der Praxis wird es wohl in der Regel funktionieren, weil Typen kein Alignment haben können, das größer ist als sie selbst und Padding damit in so einem Fall unnötig wird, aber kann man sich darauf verlassen, dass kein Compiler einem da etwas dazwischen schreibt?

    Meine Überlegungen gehen hier hauptsächlich in Richtung struct packing - wenn etwa später Speicher gespart werden soll und WindowOpt_typ gepackt wird, WindowData_typ aber nicht, darf der Compiler dann Padding in WindowData_typ zwischen die WindowOpt_typ-Member legen? Ich habe im Standard nichts gefunden, was dies ausschließt, muss allerdings zugeben, dass ich gcc gerade nicht dazu überreden kann, etwas derartiges zu tun.

    Es kann gut sein, dass ich etwas übersehen habe; wenn dem so ist, klärt mich bitte auf. Trotzdem würde ich zumindest einen Testcase anlegen, der das Layout von WindowData_typ prüft, um die Gefahr auszuschließen, beim Portieren auf eine andere Plattform plötzlich seltsame Fehler zu kriegen und keine Idee zu haben, woran es liegen könnte.


Anmelden zum Antworten