2009-06-11 11 views
6

Scrivo software in cui ogni bit deve essere esatto (è per la CPU), quindi __packed è molto importante.Problema di imballo di Union e 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; 

questa è la mia struttura e unione. Tuttavia, non funziona:

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; 

dovrebbe creare lo stesso uint32. Ma non creano la stessa cosa.

C'è qualcosa che non riesco a vedere che è sbagliato con la mia unione?

risposta

8

tua struttura ha solo 31 bit

+3

Wow. Sono stupido lol ... – Earlz

0

Tu non parlare che si sta cancellando i bit della struttura in anticipo, siete sicuri di non finire con pezzi di immondizia lasciati nel primo caso?

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

AFAIK, l'ordine in cui vengono memorizzati i bit nella struct non è definito dallo standard C99 (e lo standard C89 troppo). Molto probabilmente, i bit sono nell'ordine inverso rispetto a quello che ti aspettavi.

Avresti dovuto mostrare il risultato ottenuto e il risultato che ti aspettavi: ci aiuterebbe con la diagnosi. Il compilatore che usi e la piattaforma su cui hai eseguito potrebbe anche essere significativo.


su MacOS X 10.4.11 (PowerPC G4), questo codice:

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

produce i risultati mostrati:

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

Con l'ordine dei campi invertiti, il risultato è più quasi spiegabile:

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

Questo dà il risultato:

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

Il primo risultato ha una E come ultima cifra esadecimale perché il bit meno significativo non viene utilizzato, in quanto la struttura campo bit ha solo 31-bit definiti ..

2

Se la posizione esatta dei bit è importante, la vostra scommessa più sicura è l'imballaggio e il disimballaggio espliciti della struttura in un array di car unsigned. Tutto il resto è troppo dipendente dall'implementazione.

+0

Mi chiedo quale considerazione gli autori degli standard C abbiano dato alla nozione di consentire a strutture e/o campi di bit di essere definiti con un layout molto esplicito, riconoscendo che i compilatori probabilmente genererebbero codice inefficiente per le l'ordine o l'ordine di byte specificato non corrispondeva a quello nativo, ma almeno era in grado di generare codice efficiente quando coincidono (al contrario di dover generare sempre codice inefficiente che chiama le routine utente per costruire cose da byte). – supercat

2

Per riferimento a chiunque possa trovare questo, provare l'attributo imballato:

struct __attribute__((packed)){ 

}