سؤال

أنا أكتب بعض البرامج حيث يجب أن تكون كل بت دقيق (إنها ل CPU) لذلك __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. لكنهم لا يخلقون نفس الشيء.

هل هناك شيء لا أستطيع أن أرى هذا خطأ في اتحادي؟

هل كانت مفيدة؟

المحلول

بنية لديها 31 بت فقط

نصائح أخرى

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

النتيجة الأولى لديها ه كرقم السدس الأخير لأن أقل بت غير مستخدم، لأن هيكل حقل البت يحتوي على 31 بت فقط محددة ..

إذا كان الموضع الدقيق للتبات، فإن الرهان الأكثر أمانا هو التعبئة واضحة وتفريغ الهيكل في صفيف شار غير موقعة. أي شيء آخر يعتمد على التنفيذ للغاية.

للإشارة إلى أي شخص قد يجد هذا، جرب السمة المعبأة:

struct __attribute__((packed)){

}

أنت لا تذكر أنك تقوم بتخليص أجزاء من البنية مسبقا، هل أنت متأكد أنك لا تنتهي مع بتات القمامة التي تركت في الحالة الأولى؟

// maybe try this
page_union_t p = {0};
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top