2

I'm trying to created a linked list of structs for an EFM8 microcontroller project. I want to have the compiler allocate memory for all of the nodes at compile time. The issue I'm having is that no memory is being allocated for struct pointers.

#define FOO_QUEUE_LEN   32
 
struct Foo {
    uint8_t  bar0;
    struct Foo *next;
};
 
struct Foo queue[FOO_QUEUE_LEN];
 
void main (void)
{
    while(1) { ;; }
}

I would expect this code to allocate 4 bytes for each Foo struct (1 byte for bar0 and 3 bytes for next because in this architecture, if you don't specify memory location a 24-bit address is required.

But when debugging, the structure is reporting back only 1 byte for each struct, and expanding any of the array members shows an Error: cannot dereference this type message.

enter image description here

What's even more strange is that if you operate on the array of structs in the main loop, the size of the struct in memory is calculated correctly: queue[1].bar0 = 0xCC; will write the value to memory address 0x4. The problem being that the compile didn't allocate enough memory so we're overwiting past the bounds of each struct (in this case, 0xCC ends up at queue[4].bar0).

Is there some directive that is needed to size these struct pointers correctly at compile time?

Mike Szczys
  • 125
  • 1
  • 10
  • 5
    I would expect it to be the artifact of the debugger. What happens if you just print the sizeof value? – SergeyA Aug 02 '21 at 18:16
  • Thank you @SergeyA, you have solved this for me. In the main loop, adding a variable to store sizeof(queue) and a dummy to store 0xCCCC, I can see where the array of structs ends and it is allocated correctly. Much appreciated! – Mike Szczys Aug 02 '21 at 18:40

1 Answers1

2

The comment from SergeyA is the correct answer:

I would expect it to be the artifact of the debugger. What happens if you just print the sizeof value?

Consider this expanded version of the program:

#define FOO_QUEUE_LEN   32

struct Foo {
    uint8_t  bar0;
    struct Foo* next;
};

struct Foo xdata queue[FOO_QUEUE_LEN];




void zeroFooStruct(struct Foo *fooPacket) {
    // Using FF for debugging so I can see memory writes
    fooPacket->bar0 = 0xFF;
    fooPacket->next = 0;
}

void initializeFooQueue(void)
{
    uint8_t i;
    struct foo *previous;

    previous = NULL;

    // This linked list is a FILO
    for (i=0; i<FOO_QUEUE_LEN; i++)
    {
        zeroFooStruct(&queue[i]);
        queue[i].next = previous;
        previous = &queue[i];
    }
}

void main (void)
{
    uint16_t s;
    uint16_t mydata = 0xCCCC;
    initializeFooQueue();

    s = sizeof(queue);

    while(1) { ;; }
}

We can see that for each node we're storing 0xFF for bar0 and the address to the previous node. 4 bytes times 32 nodes = 0x80 memory slots. That memory space then has our expected sizeof value (0x0080) followed by our dummy value (0xCCCC), showing that there is indeed a correct amount of memory allocated and it's the debugger that's not displaying the memory correctly.

enter image description here

Mike Szczys
  • 125
  • 1
  • 10
  • note that the way your list is linked with the variable name you've chosen is confusing. `next` actually points to the previous element (assuming that `queue[0]` is the head of your list, and if you consider `queue[FOO_QUEUE_LEN-1]` to be your head that's equally confusing IMO). – yano Aug 02 '21 at 19:03
  • 1
    Yes, that's a good point. This is actual an abstract from a larger program where there are two FILO buffers made from the same array of structs. That array itself is kept inside another struct that has pointers to the first element in each of those two lists. So the actual order in the array doesn't matter as the linked list can order them in any combination. What's important to me is to have the memory allocated at compile time. – Mike Szczys Aug 02 '21 at 22:38