Union og struct pakking problem

stemmer
6

Jeg skriver noe programvare der hver bit må være nøyaktig (det er for CPU) så __packed er svært viktig.

typedef union{
uint32_t raw;
struct{
    unsigned int present:1;
    unsigned int rw:1;
    unsigned int user:1;
    unsigned int dirty:1;
    unsigned int free:7;
    unsigned int frame:20;
} __packed;
}__packed page_union_t;

det er min struktur og union. Det virker imidlertid ikke:

page_union_t p; //.....
//This:
p.frame=trg_page;
p.user=user;
p.rw=rw;
p.present=present;
//and this:
p.raw=trg_page<<12 | user<<2 | rw<<1 | present;

bør skape den samme uint32. Men de ikke skaper det samme.

Er det noe jeg ikke kan se at er galt med min fagforening?

Publisert på 11/06/2009 klokken 02:37
kilden bruker
På andre språk...                            


5 svar

stemmer
8

Din struct har bare 31 bits

Svarte 11/06/2009 kl. 02:44
kilden bruker

stemmer
6

AFAIK, er rekkefølgen i hvilken bitene i struct lagres udefinert av C99-standarden (og C89 standard for). Mest sannsynlig, biter er i omvendt rekkefølge fra hva du forventet.

Du skulle ha vist det resultatet du fikk, så vel som det resultatet du forventet - det ville hjelpe oss med diagnosen. Kompilatoren du bruker og plattformen du kjører på kan også være betydelig.


På MacOS X 10.4.11 (PowerPC G4), denne koden:

#include <inttypes.h>
#include <stdio.h>

typedef union
{
        uint32_t raw;
        struct
        {
                unsigned int present:1;
                unsigned int rw:1;
                unsigned int user:1;
                unsigned int dirty:1;
                unsigned int free:7;
                unsigned int frame:20;
        };
} page_union_t;

int main(void)
{
        page_union_t p = { .raw = 0 }; //.....
        unsigned trg_page = 0xA5A5A;
        unsigned user = 1;
        unsigned rw = 1;
        unsigned present = 1;

        p.frame = trg_page;
        p.user = user;
        p.rw = rw;
        p.present = present;

        printf("p.raw = 0x%08X\n", p.raw);

        p.raw = trg_page<<12 | user<<2 | rw<<1 | present;
        printf("p.raw = 0x%08X\n", p.raw);

        p.raw <<= 1;
        printf("p.raw = 0x%08X\n", p.raw);
        return(0);
}

gir de resultatene som er vist:

p.raw = 0xE014B4B4
p.raw = 0xA5A5A007
p.raw = 0x4B4B400E

Med rekkefølgen på feltene reversert, er resultatet mer nesten forklarlig:

#include <inttypes.h>
#include <stdio.h>

typedef union
{
        uint32_t raw;
        struct
        {
                unsigned int frame:20;
                unsigned int free:7;
                unsigned int dirty:1;
                unsigned int user:1;
                unsigned int rw:1;
                unsigned int present:1;
        };
} page_union_t;

int main(void)
{
        page_union_t p = { .raw = 0 }; //.....
        unsigned trg_page = 0xA5A5A;
        unsigned user = 1;
        unsigned rw = 1;
        unsigned present = 1;

        p.frame = trg_page;
        p.user = user;
        p.rw = rw;
        p.present = present;

        printf("p.raw = 0x%08X\n", p.raw);

        p.raw = trg_page<<12 | user<<2 | rw<<1 | present;
        printf("p.raw = 0x%08X\n", p.raw);

        p.raw <<= 1;
        printf("p.raw = 0x%08X\n", p.raw);
        return(0);
}

Dette gir resultatet:

p.raw = 0xA5A5A00E
p.raw = 0xA5A5A007
p.raw = 0x4B4B400E

Den første resultat har en E som den siste heksasiffer fordi den minst signifikante bit ikke benyttes, fordi det bit-feltkonstruksjon har bare 31 biter er definert ..

Svarte 11/06/2009 kl. 02:46
kilden bruker

stemmer
2

For referanse til noen som kan finne dette, kan du prøve pakket attributt:

struct __attribute__((packed)){

}
Svarte 07/04/2017 kl. 04:31
kilden bruker

stemmer
2

Hvis den nøyaktige plasseringen av biter saker, er det tryggeste veddemålet eksplisitt pakking og utpakking av strukturen til en unsigned char array. Noe annet er for implementering avhengig.

Svarte 11/06/2009 kl. 03:20
kilden bruker

stemmer
0

Du trenger ikke nevne at du er clearing ut biter av strukturen på forhånd, er du sikker på at du ikke ender opp med søppel biter til overs i det første tilfellet?

// maybe try this
page_union_t p = {0};
Svarte 11/06/2009 kl. 02:45
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more