2009-06-11 14 views
6

Estoy escribiendo algún software donde cada bit debe ser exacto (es para la CPU) así que __packed es muy importante.Problema de empaquetamiento de unión y estructura

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; 

que es mi estructura y unión. Sin embargo, no funciona:

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; 

debe crear el mismo uint32. Pero ellos no crean lo mismo.

¿Hay algo que no veo que esté mal en mi unión?

Respuesta

8

Su estructura tiene sólo 31 bits de

+3

Wow. Soy tonto, lol ... – Earlz

0

Usted no menciona que se están limpiando los bits de la estructura de antemano, ¿está seguro de que no está terminando con trozos sobrantes de basura en el primer caso?

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

AFAIK, el orden en que se almacenan los bits en el struct está definido por el estándar C99 (y el estándar C89 también). Lo más probable es que los bits estén en el orden inverso al esperado.

Debería haber mostrado el resultado que obtuvo y el resultado esperado: nos ayudaría con el diagnóstico. El compilador que utiliza y la plataforma en la que se ejecuta también pueden ser importantes.


En MacOS X 10.4.11 (PowerPC G4), este código:

#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 los resultados mostrados:

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

Con el orden de los campos invierte, el resultado es más explicable:

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

Esto da el resultado:

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

El primer resultado tiene un E como el último dígito hexadecimal ya que el bit menos significativo no se utiliza, ya que la estructura del campo de bits tiene sólo 31 bits definidos ..

2

Si importa la posición exacta de los bits, la apuesta más segura es empaquetar y desempaquetar explícitamente la estructura en una matriz de caracteres sin signo. Cualquier otra cosa depende demasiado de la implementación.

+0

Me pregunto qué consideración han dado los autores de los estándares C a la noción de permitir que las estructuras y/o campos de bits se definan con un diseño muy explícito, reconociendo que los compiladores probablemente generarían un código ineficiente para las estructuras cuya el orden o empaquetado de bytes especificado no coincide con el original, pero al menos puede generar código eficiente cuando coinciden (en lugar de tener que generar siempre código ineficiente que llama a las rutinas del usuario para construir cosas a partir de bytes). – supercat

2

Para referencia a cualquier persona que pudiera encontrar esto, tratar el atributo embalado:

struct __attribute__((packed)){ 

} 
Cuestiones relacionadas