Bit fields maked more optimized

1k Views Asked by At

I'm making some code for a 16 bits microprocessor. My memory is quite limited at 128 KB. IAR C/C++ Compiler for MSP430 I need to implement some code to save some memory.

I tried to implemented this with this C characteristic implementation.

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

But with this bit of code I still only use 1 bit of a 16 bit word.

My goal is to use the same word sized bit of memory for two 8 bit variables. The first variable should be 8 bits left of the second variable.

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

Is this possible? Are there any implementations of this or is there a library in C for this? How should I go about doing this?

3

There are 3 best solutions below

5
On

You shouldn't use bit-fields for any purpose, particularly not for memory mapping, since they are very poorly standardized.

What you should do is to use the stdint.h types. Declare two uint8_t variables. You save memory in microcontrollers by carefully picking the necessary type whenever declaring a variable.

For example, in professional programs for limited microcontrollers, a typical for loop is written as for(uint8_t i=0; ... and not with "sloppy typing" for(int i=0; ....

The trick is: whenever you declare any variable, then always consider what is the maximum value that variable might get. By doing so, you save memory and prevent overflow bugs.

0
On

If you want to save memory just use smaller types when you declare the struct

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

it makes code easier to read debug and modify.

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"

Many uCs have special instructions to extract bitfields move them to the lower bits and signed and unsigned extend the result to the register/variable size

0
On

You haven't told us what specific platform you are using so I can't give you a detailed enough answer but what you want is to remove the padding from your struct. Or in other words you want to pack your structs.

This is how I understand you to want your memory layout to be two bytes in one 16 bit word.

struct {
    uint8_t widthValidated;
    uint8_t heightValidated;
} status;

To require the compiler to create a certain boundary you can do:

for arm:

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

for gcc:

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

Your platform may differ but it should come up how to do this when you search for struct packing.

A union inside the struct would also be an option but this wouldn't necessarily be portable as bit/byte ordering may differ from platform to platform.

You see me using uint8_t above . This is a typedef done inside <stdint.h>. This is a standardized way to declare an integer variable with a defined width. Useful types inside a microcontroller are the undefined integer family of: uint8_t (8-bits), uint16_t (16-bits) and uint32_t (32-bits). And their signed counterparts: int8_t (8-bits), int16_t (16-bits) and int32_t (32-bits).