Битовые поля сделаны более оптимизированными

Я делаю код для 16-битного микропроцессора. Моя память довольно ограничена в 128 КБ. Компилятор IAR C/C++ для MSP430 Мне нужно реализовать некоторый код для экономии памяти.

Я попытался реализовать это с помощью этой характерной реализации C.

struct {
    unsigned int widthValidated : 1;
    unsigned int heightValidated : 1;
} status;

Но с этим битом кода я все еще использую только 1 бит 16-битного слова.

Моя цель - использовать бит памяти одного размера для двух 8-битных переменных. Первая переменная должна быть на 8 бит слева от второй переменной.

struct {
   unsigned int widthValidated : 8; //8 bits for this
   unsigned int heightValidated : 8; // 8 left over for this
} status;

Это возможно? Есть ли реализации этого или есть библиотека в C для этого? Как мне это сделать?

3 ответа

Не следует использовать битовые поля для каких-либо целей, особенно для отображения памяти, поскольку они очень плохо стандартизированы.

Что вы должны сделать, это использовать stdint.h типы. Объявить два uint8_t переменные. Вы экономите память в микроконтроллерах, тщательно выбирая необходимый тип при объявлении переменной.

Например, в профессиональных программах для ограниченных микроконтроллеров типичный цикл for записывается как for(uint8_t i=0; ... а не с "небрежной печатью" for(int i=0; ...,

Хитрость заключается в следующем: всякий раз, когда вы объявляете какую-либо переменную, всегда учитывайте, какое максимальное значение может получить эта переменная. Тем самым вы экономите память и предотвращаете ошибки переполнения.

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

Как я понимаю, вы хотите, чтобы размер вашей памяти составлял два байта в одном 16-битном слове.

struct {
    uint8_t widthValidated;
    uint8_t heightValidated;
} status;

Требовать от компилятора создания определенной границы вы можете:

для руки:

struct __attribute__((packed)){
    uint8_t widthValidated;
    uint8_t heightValidated;
} status;

для gcc:

#pragma pack (1)
struct __attribute__((packed)){
    uint8_t widthValidated;
    uint8_t heightValidated;
} status;

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

Объединение внутри структуры также может быть вариантом, но это не обязательно будет переносимым, так как порядок следования битов / байтов может отличаться от платформы к платформе.

Вы видите меня, используя uint8_t выше. Это typedef сделано внутри <stdint.h>, Это стандартизированный способ объявления целочисленной переменной определенной ширины. Полезные типы внутри микроконтроллера - это неопределенное целочисленное семейство: uint8_t (8 бит), uint16_t (16 бит) и uint32_t (32 бит). И их подписанные коллеги: int8_t (8 бит), int16_t (16 бит) и int32_t (32 бит).

Если вы хотите сэкономить память, просто используйте меньшие типы при объявлении структуры

typedef struct
{
    uint8_t flag1: 1;
    uint8_t flag2: 1;
    uint8_t flag3: 1;
    uint8_t flag4: 1;
    uint8_t flag5: 1;
}myflags;

uint8_t foo(myflags f)
{
    return f.flag4;
}

uint8_t foo1(uint8_t flags)
{
    return !!(flags & (1 << 3));
}

void foo3()
{
    printf("%zu\n", sizeof(myflags));
}

это облегчает чтение кода, отладку и изменение.

foo:
        ubfx    r0, r0, #3, #1
        bx      lr
foo1:
        ubfx    r0, r0, #3, #1
        bx      lr
foo3:
        movs    r1, #1
        ldr     r0, .L5
        b       printf
.L5:
        .word   .LC0
.LC0:
        .ascii  "%zu\012\000"

Многие СК имеют специальные инструкции для извлечения битовых полей, перемещают их в младшие биты и подписывают, а без знака расширяют результат до размера регистра / переменной.

Другие вопросы по тегам