2009-06-11 12 views
6

Piszę o oprogramowaniu, w którym każdy bit musi być dokładny (dotyczy CPU), dlatego __packed jest bardzo ważne.Problem zwiĘ ... zku z uklĘ ... giem Union i struct

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; 

czyli moja struktura i związek. Nie działa jednak:

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; 

powinien utworzyć ten sam Uint32. Ale nie tworzą tego samego.

Czy jest coś, czego nie widzę, że jest źle z moim związkiem?

Odpowiedz

8

Twój struct ma tylko 31 bitów

+3

Wow. Jestem głupi ... – Earlz

0

Nie wspominając, że są oczyszczaniu bity struktury wcześniej, to na pewno nie kończą się z bitów śmieci pozostawionych w pierwszym przypadku?

// maybe try this 
page_union_t p = {0}; 
6

AFAIK, kolejność, w jakiej bity w struktury są przechowywane jest zdefiniowana przez standard C99 (a standardem C89 zbyt). Najprawdopodobniej bity są w odwrotnej kolejności niż oczekiwano.

Powinieneś pokazać wynik, który otrzymałeś, a także oczekiwany rezultat - pomoże nam to w postawieniu diagnozy. Kompilator, którego używasz i platforma, na której działasz, może być znaczący.


na MacOS X 10.4.11 (PowerPC G4), ten kod:

#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); 
} 

produkuje wyniki przedstawiono:

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

Z rzędu pól odwrócone, wynik jest bliżej wyjaśnienia:

#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); 
} 

To daje wynik:

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

Pierwszy wynik jest E jako ostatnią cyfrą sześciokątnym ponieważ najmniej znaczący bit nie jest stosowana, ponieważ struktura bitowe pole ma tylko 31 bitów określone ..

2

Jeśli dokładna pozycja bitów ma znaczenie, najbezpieczniejszym zakładem jest jawne upakowanie i rozpakowanie struktury w niepodpisaną tablicę znaków. Coś innego jest zależne od implementacji.

+0

Zastanawiam się, jakie względy autorzy standardów C nadali koncepcji pozwalającej zdefiniować struktury i/lub pola bitowe z bardzo wyraźnym układem, uznając, że kompilatory prawdopodobnie wygenerują nieefektywny kod dla struktur, których określona kolejność bajtów lub pakowanie nie pasują do natywnego, ale przynajmniej są w stanie wygenerować efektywny kod, gdy się zgadzają (w przeciwieństwie do konieczności generowania zawsze nieefektywnego kodu, który wywołuje procedury użytkownika w celu budowania rzeczy z bajtów). – supercat

2

Dla odniesieniu do każdego, kto może znaleźć tego, spróbuj zapakowany atrybut:

struct __attribute__((packed)){ 

}