Jump to content

union of pointer-types


avogra

Recommended Posts

Hi,

i'm working on a menu-engine for some time now. after struggling (and learning) a lot with (about) pointers, structs and unions the last 2 days, i'm finally stuck now :) I'll post the problem first, then what i need this for.

--the problem--

one of the fields in a struct (for the menu-entries) should hold a pointer to either a function or a string. so lets have a union in the struct:

void testfunc(void)
{
}
unsigned char teststring[]={"i'm a teststring"};

typedef struct {
  // i have dropped all variables here, not affecting the problem
  union {
    const unsigned char (*const text);              //pointer to string
    const void (*const menu_func)(unsigned char);   //pointer to menu-function
  };
} test_t;

const test_t menu[2] = {{&testfunc},{&teststring}}; //initialize the test-menu

compiles fine, but when i look into the asm code, menu contains 4*3 bytes, so it seems the compiler has converted the union into a struct without telling me:
_test  db  LOW(_testfunc), HIGH(_testfunc), UPPER(_testfunc), 0x00, 0x00, 0x00, LOW(_teststring), HIGH(_teststring), 0x80, 0x00, 0x00, 0x00
when i remove the outer struct, so that test_t is a union, it compiles as i expect:
_test:
  DB  LOW(_testfunc), HIGH(_testfunc), UPPER(_testfunc), LOW(_teststring), HIGH(_teststring), 0x80
i googled a lot and also discovered, that there have been many bugs in sdcc concerning initialization of unions, but they were either fixed or don't apply to this case. same happens in sdcc 2.8.0 and 2.9.0. have a clue? --what i need this for-- each menu-entry should have a small footprint in order to pack as many entries as possible into the 256byte-limit, and to safe code-space (even if i still have plenty left). it should be possible to enter submenus, change numeric values and change strings. what i came up with is an array of structs with each struct of 5 bytes holding 1 entry. each entry can be 1 of 4 types: type 0: submenu -> you can choose between several followup-entries (e.g. for selecting "midi-setup", "pots", "buttons", ....) type 1: multmenu -> you can choose between many values, all pointing to the same followup-entry (e.g. for selecting pot1-64) type 2: editval -> edit a numerical value type 3: edittxt -> edit a string depending on this type, the bytes of an entry have different meaning:
byte0                                     byte1                        byte2-4
  bit6+7:      bit0-5:
  00:submenu   index of first subentry   number of subentries    pointer to entry-function (mainly for handling display stuff)
  01:mltmenu   index of subentry         number of subentries    pointer to entry-function (mainly for handling display stuff)
  10:editval   minimum value             maximum value           pointer to edit-function
  11:editstr   unused                    length of string        pointer to string

i then would track the way taken through the menu in a small array (2bytes per menu-level), so i find back to where i was before, when i exit an entry. at the same time, i can read it to see earlier selections. e.g. when i alter a value for a button, that was selected in a multmenu. then i have to look up, which one it was.

i took this whole approach to be flexible, when extending the menu. if you can follow my thoughts, any comments are very welcome :)

concerning this union: i certainly could use a function-pointer to a stringedit-function as well and do stuff there (possibly better anyway) or even drop it entirely and do this with the other types. still i'm curious, why the compiler acts the way it does.

thanks for reading or maybe even some input :)

Alex

Link to comment
Share on other sites

Hi Alex,

It looks like its doing some alignment on the struct and zero filling with 3 bytes of zero for each struct in the array.  I say this because each item has three zeros after it and that seems like a clue.  If it is doing this, then the union elements are still working as you'd expect, its just that memory is being wasted in a different way than you might think.  You could check this by taking the address of each element of the union.

if (&menu[0].text == &menu[0].menu_func) {

  // then everything is still ok

}

It does seem to me that you can simply get rid of the struct all together.  Something like this:

typedef union {

    const unsigned char (*const text);              //pointer to string

    const void (*const menu_func)(unsigned char);  //pointer to menu-function

} MenuItemType;

MenuItemType menu[2] = {&testfunc,&teststring}

Struct and union are actually quite similar to each other.  Union is just a struct that has the additional condition that each item in it shares the same memory space.

Link to comment
Share on other sites

I just tried to find out, what it's doing there by adding some char-vars and -unions.

when i add a simple char behind the union and add an according value (i took 0xef and 0xff) to the initialization, asm will look like that:

_menu  db  LOW(_testfunc), HIGH(_testfunc), UPPER(_testfunc), 0xef, 0x00, 0x00, LOW(_teststring), HIGH(_teststring), 0x80, 0xff, 0x00, 0x00
that seems to confirm what you said. but why does it do so? but when i add a simple union of 2 chars in front of the pointer-union, i seem to be completely unable to get it compiled:
main.c:37: error 2: Initializer element is not constant
main.c:37: error 2: Initializer element is not constant
make: *** [_output/main.o] Error 1

no matter, how i distribute the values or how i set braces.

when i have a union of only 1 char in front, it compiles again  ???

i want the complete struct to take 5bytes in total (including 2x char). that would let me populate the array with 51 elements (256/5). currently, i'm using up 27, enough headroom for future menu-entries. dropping the union leads to a footprint of 8bytes -> max 32 elements. that works now, but

Link to comment
Share on other sites

hihi, i just played around quite aimlessly and suddenly got this message from the compiler:

INCOMPLETE SUPPORT FOR INITIALIZED union---FALLING BACK TO struct
This is a bug. Please file a bug-report with your source attached.
INCOMPLETE SUPPORT FOR INITIALIZED union---FALLING BACK TO struct
This is a bug. Please file a bug-report with your source attached.
gplink -s C:\Programme\MIOS_base/etc/lkr/p18f452.lkr -m -o project.hex  C:\Programme\MIOS_base/lib/libsdcc.lib C:\Programme\MIOS_base/lib/pic18f452.lib _output/main.o

tried it with sdcc 2.9.0, and error was gone, instead, where the 3 pointer bytes should be, it's only 0x00,0x00,0x00

i'll look into the bug list once more and meanwhile look for an alternative solution. maybe a void-pointer, cast to the right type before use.

Cheers,

Alex

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...