View previous topic :: View next topic |
Author |
Message |
SamMeredith
Joined: 13 Jul 2018 Posts: 23
|
ROM structs with self-referencing elements |
Posted: Wed Oct 06, 2021 8:31 am |
|
|
I am trying to store some menus in a tree:
Code: |
#device CONST=ROM
typedef struct menu {
uint8_t id;
char const *text;
struct menu *children[MAX_CHILDREN];
} menu_t;
|
which I then use like:
Code: |
menu_t submenu = {
...
};
const char main_menu_text[MAX_MENU_TEXT] = "Main Menu";
menu_t main_menu = {
MAIN_MENU_ID,
main_menu_text,
{
&submenu
}
};
|
This is working fine.
However my entire menu is constant and so I would like to store the whole thing in ROM, rather than just the text.
What I want to do is change all my menu_t to const menu_t. This compiles but fails when attempting to traverse submenus. I think I need to adjust my struct to store children as pointers to ROM.
This is where I run into problems. If I adjust my struct to:
Code: |
typedef struct menu {
uint8_t id;
char const *name;
struct menu const *children[MAX_CHILDREN];
} menu_t;
|
This no longer compiles, giving me the error
Quote: | Error#43 Expecting a declaration |
From other tests, the pattern struct foo const *bar seems to work. It is only when self referencing that it fails to compile.
I have also tried manually calling read_program_memory() to access the submenus, but the child pointers contain RAM addresses (though I'm not sure what they're pointing at) and this fails.
Is it possible to do what I'm attempting here (effectively storing tree nodes in ROM)?
I'm using compiler version 5.101 on a dsPIC33. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19503
|
|
Posted: Wed Oct 06, 2021 9:15 am |
|
|
Certain types of pointer references from inside structures have always had
issues with CCS. I've in the past found that it is actually much safer to
not declare the pointers as being to a structure, but instead as just a large
enough integer. Then explicitly cast the value to being a pointer of the
required type when you use it. |
|
|
SamMeredith
Joined: 13 Jul 2018 Posts: 23
|
|
Posted: Wed Oct 06, 2021 10:07 am |
|
|
Thanks, that works.
Code: |
typedef struct menu {
uint8_t id;
char const *text;
//struct menu const *children[MAX_CHILDREN];
int32_t const *children[MAX_CHILDREN];
} menu_t;
|
and then implicitly casting
Code: |
menu_t const *child = menu->children[i];
|
lets me use the structure the way I wanted.
I couldn't explicitly cast to menu_t const * (compiler error) and casting to menu_t * would truncate the address and break things.
I think this also explains what the non-const struct pointers were doing, truncating the ROM address, and hence why read_program_memory() didn't work.
Makes me wonder what the difference is between the int32_t const * member and struct menu const * member.
Probably beyond my knowledge of the compiler, but I'll trawl through the .lst file tomorrow and see if I can make any sense of it.
Last edited by SamMeredith on Wed Oct 06, 2021 10:24 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19503
|
|
Posted: Wed Oct 06, 2021 10:23 am |
|
|
Key thing in the PIC, is to understand that the ROM and RAM have
two separate address spaces. This makes 'pointers' to ROM, quite
difficult to implement. The compiler tricks that allow this to happen seem
to get confused when the item is inside things like structures, while
the explicit cast forces the correct access to be done. |
|
|
|