Проблема объединения и структурирования - PullRequest
6 голосов
/ 11 июня 2009

Я пишу некоторое программное обеспечение, где каждый бит должен быть точным (это для процессора), поэтому __packed очень важен.

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;

это моя структура и союз. Однако это не работает:

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;

должен создать тот же uint32. Но они не создают одно и то же.

Есть что-то, чего я не вижу, что не так с моим союзом?

Ответы [ 5 ]

8 голосов
/ 11 июня 2009

Ваша структура имеет только 31 бит

6 голосов
/ 11 июня 2009

AFAIK, порядок хранения битов в структуре не определен стандартом C99 (и стандартом C89 тоже). Скорее всего, биты в порядке, обратном тому, что вы ожидали.

Вы должны были показать результат, который вы получили, а также результат, который вы ожидали - это поможет нам с диагнозом. Компилятор, который вы используете, и платформа, на которой вы работаете, также могут иметь значение.


В MacOS X 10.4.11 (PowerPC G4) этот код:

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

дает показанные результаты:

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

При обратном порядке полей результат становится почти объяснимым:

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

Это дает результат:

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

Первый результат имеет E как последнюю шестнадцатеричную цифру, потому что младший значащий бит не используется, потому что в структуре битового поля определены только 31 бит.

2 голосов
/ 07 апреля 2017

Для ссылки на любого, кто может найти это, попробуйте упакованный атрибут:

struct __attribute__((packed)){

}
2 голосов
/ 11 июня 2009

Если точная позиция битов имеет значение, ваша самая безопасная ставка - явная упаковка и распаковка структуры в массив без знака. Все остальное слишком зависит от реализации.

0 голосов
/ 11 июня 2009

Вы не упоминаете, что предварительно очищаете биты структуры, вы уверены, что в первом случае у вас не осталось мусорных битов?

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