Pergunta

Eu estou escrevendo algum software onde cada bit deve ser exato (que é para o CPU) para __packed é muito importante.

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 é a minha estrutura e união. Ele não funciona no entanto:

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;

devem criar o mesmo uint32. Mas eles não criam a mesma coisa.

Existe algo que eu não posso ver o que está errado com a minha união?

Foi útil?

Solução

A sua estrutura tem apenas 31 bits

Outras dicas

AFAIK, a ordem em que os bits na struct são armazenados é indefinido pelo padrão C99 (e o padrão C89 também). Muito provavelmente, os bits são na ordem inversa do que você esperava.

Você deveria ter mostrado o resultado que você tem, bem como o resultado que você espera - seria nos ajudar com o diagnóstico. O compilador que você usa e a plataforma que você rodar em também poderia ser significativo.


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

produz os resultados mostrado:

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

Com a ordem dos campos invertidos, o resultado é mais quase explicável:

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

Isto dá o resultado:

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

O primeiro resultado tem um E como o último digito hexadecimal porque o bit menos significativo não é utilizada, porque a estrutura de campo de bit tem apenas 31 bits definidos ..

Se a posição exata de bits importa, sua aposta mais segura é a embalagem explícita e descompactação da estrutura em uma matriz de char não assinado. Qualquer outra coisa que é muito dependente de implementação.

Para referência para qualquer pessoa que pode achar isso, tente o atributo embalado:

struct __attribute__((packed)){

}

Você não mencione que você está limpando os bits da estrutura de antemão, você tem certeza que você não está terminando com pedaços de lixo que sobraram no primeiro caso?

// maybe try this
page_union_t p = {0};
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top