|  | Some issue with pointers |  | |
| | | Marco Trapanese |  |
| Posted: Mon Jun 30, 2008 4:56 pm Post subject: Some issue with pointers |  |
| |  | |
Hello,
I need some help to understand what I'm doing :)
I'm writing code for an embedded system and I need to create a navigable menu system. I'm going to use these structures:
typedef struct { char *name[2]; int type; int num_param; void *ptr; } menuitem_t;
typedef struct { char *name[2]; int num_items; menuitem_t *items; } menu_t;
The latter defines each menu or submenu with a name, a number of items and a pointer to the items structure.
The former defines each menu item with a name, a type (see below) the number of parameters - if any - and finally a generic pointer (see below again).
In this way I can generate menus of any complexity and very flexible. The void pointer should point to another menu_t struct if the item leads to a submenu, to an array if it leads to a parameter list. But it could also leads to a function if the selection of this item needs an action to be executed.
Actually I have two questions:
1) I can't cast correctly the void *ptr. Let's say I want to access to:
char *par[] = {"First", "Second"};
ot invoke:
void myfunc();
Please, may you help me to understand how to cast and then to use that pointer in these cases?
2) It would be nice if I can know the path the user is following. For example:
mainmenu -> seconditem -> firstitem
where each of these entities are menu_t structs. How would you implement such a dynamic path?
Thank you and I apologize for my poor English Marco / iw2nzm |
| |
| | | Ben Bacarisse |  |
| Posted: Mon Jun 30, 2008 9:00 pm Post subject: Re: Some issue with pointers |  |
| |  | |
Marco Trapanese <marcotrapaneseNOSPAM@gmail.com> writes:
| Quote: | I'm writing code for an embedded system and I need to create a navigable menu system. I'm going to use these structures:
typedef struct { char *name[2]; int type; int num_param; void *ptr; } menuitem_t;
typedef struct { char *name[2]; int num_items; menuitem_t *items; } menu_t;
The latter defines each menu or submenu with a name, a number of items and a pointer to the items structure.
The former defines each menu item with a name, a type (see below) the number of parameters - if any - and finally a generic pointer (see below again).
|
I can't see why you'd have two. I'd merge them like this:
typedef struct menu { char *name[2]; int type; int num_param; union { void *vp; struct menu *items; } ptr; } menu_t;
It must be simpler to have only one type (in the C sense) for menu items, surely?
| Quote: | In this way I can generate menus of any complexity and very flexible. The void pointer should point to another menu_t struct if the item leads to a submenu, to an array if it leads to a parameter list. But it could also leads to a function if the selection of this item needs an action to be executed.
|
Function pointers are "special" in that there is no guarantee in C that you can convert a void * to function pointer (nor vice versa). Your implementation may offer this as an extension, but if you use a union, you can add a function pointer type and not have any portability worries.
| Quote: | Actually I have two questions:
1) I can't cast correctly the void *ptr. Let's say I want to access to:
char *par[] = {"First", "Second"};
|
Let's say that ptr got set like this: 'ptr = par;'. ptr is then a char ** in disguise so simply writing:
char **strings = ptr;
would let you access strings[0] and strings[1].
| Quote: | ot invoke:
void myfunc();
Please, may you help me to understand how to cast and then to use that pointer in these cases?
|
It is easiest not to use a cast. Just assign ptr to a variable of the right type and off you go.
However, since this requires an extension to standard C, you might want to consider using a union containing an element for each pointer type you need. This means you don't have to reply on converting a void * to a function pointer and it keeps the code very clean (at the expense of a messy union).
| Quote: | 2) It would be nice if I can know the path the user is following. For example:
mainmenu -> seconditem -> firstitem
where each of these entities are menu_t structs. How would you implement such a dynamic path?
|
I'd use a stack, probably implemented as a linked list.
-- Ben. |
| |
| | | Marco Trapanese |  |
| Posted: Tue Jul 01, 2008 7:17 am Post subject: Re: Some issue with pointers |  |
| |  | |
Ben Bacarisse ha scritto:
| Quote: | I can't see why you'd have two. I'd merge them like this:
typedef struct menu { char *name[2]; int type; int num_param; union { void *vp; struct menu *items; } ptr; } menu_t;
It must be simpler to have only one type (in the C sense) for menu items, surely?
|
You're right, it's my fault. I'm not so experienced (yet) in this kind of thing!
| Quote: | Function pointers are "special" in that there is no guarantee in C that you can convert a void * to function pointer (nor vice versa).
|
What a pity! :)
| Quote: | Your implementation may offer this as an extension, but if you use a union, you can add a function pointer type and not have any portability worries.
|
So, are you suggesting to add in the union a pointer for each type I need, aren't you? Or at least, the function pointer because is treated differently.
| Quote: | char *par[] = {"First", "Second"};
Let's say that ptr got set like this: 'ptr = par;'. ptr is then a char ** in disguise so simply writing:
char **strings = ptr;
would let you access strings[0] and strings[1].
|
Ok, I was trying to access directly from ptr with a cast. But it's more readable you solution.
| Quote: | It is easiest not to use a cast. Just assign ptr to a variable of the right type and off you go.
However, since this requires an extension to standard C, you might want to consider using a union containing an element for each pointer type you need. This means you don't have to reply on converting a void * to a function pointer and it keeps the code very clean (at the expense of a messy union).
|
Ok, this answer my first question above. I read the 'type' value and use the correct union entry. The others will be ignored.
| Quote: | I'd use a stack, probably implemented as a linked list.
|
I got it.
Thank you a lot for the time you spent!
Marco / iw2nzm |
| |
| | | Marco Trapanese |  |
| Posted: Tue Jul 01, 2008 8:09 am Post subject: Re: Some issue with pointers |  |
| |  | |
Ben Bacarisse ha scritto:
| Quote: | I can't see why you'd have two. I'd merge them like this:
typedef struct menu { char *name[2]; int type; int num_param; union { void *vp; struct menu *items; } ptr; } menu_t;
|
Please, consider this short code:
char mypar[3]; void myfunc();
typedef struct menu { char *name[2]; int type; int num_param; union { void *vp; void (*fp)(); struct menu *items; } ptr; } menu_t;
Ok, now I want to initialize this struct:
const menu_t mn_mnu = { {"Main Menu", "Menu"}, MIT_FUNCTION, 0, {mypar} };
It successfully compiles. Please note that the function pointer declaration in Dynamic C is slightly different from standard-C. The syntax is the same: returntype (*name)(); also for functions with parameters.
Now I want to initialize the second (and eventually the third) element of the union. How should I do?
{, myfunc} {0, myfunc} {NULL, myfunc}
None of these works. The compiler screams loud a lot of errors. I'm googled on this but I didn't find an example.
Bye Marco / iw2nzm |
| |
| | | Ben Bacarisse |  |
| Posted: Tue Jul 01, 2008 11:56 am Post subject: Re: Some issue with pointers |  |
| |  | |
I'll keep my replies to this thread. In the other reply you asked a question. Imagine that I relied to it "yes".
Marco Trapanese <marcotrapaneseNOSPAM@gmail.com> writes:
| Quote: | Ben Bacarisse ha scritto:
I can't see why you'd have two. I'd merge them like this:
typedef struct menu { char *name[2]; int type; int num_param; union { void *vp; struct menu *items; } ptr; } menu_t;
Please, consider this short code:
char mypar[3]; void myfunc();
typedef struct menu { char *name[2]; int type; int num_param; union { void *vp; void (*fp)(); struct menu *items; } ptr; } menu_t;
Ok, now I want to initialize this struct:
const menu_t mn_mnu = { {"Main Menu", "Menu"}, MIT_FUNCTION, 0, {mypar} };
It successfully compiles. Please note that the function pointer declaration in Dynamic C is slightly different from standard-C. The syntax is the same: returntype (*name)(); also for functions with parameters.
Now I want to initialize the second (and eventually the third) element of the union. How should I do?
{, myfunc} {0, myfunc} {NULL, myfunc}
|
You need to either
(1) Use C99 designated initialiser syntax:
{ .fp = myfunc }
(2) Let the compiler complain about the type-mismatch (if it works):
{ myfunc }
(3) Convert to void * (again, if that is permitted):
{ (void *)myfunc }
You don't loose anything this way. In your method, you were still going to have to initialise a void * with a function pointer which is what the above does (with C99 you can only initialise the first element of a union).
Of course, you can do it at runtime (mn_mnu.ptr.fp = myfunc;) but then you can have the menu as const.
-- Ben. |
| |
| | | Marco Trapanese |  |
| Posted: Tue Jul 01, 2008 1:52 pm Post subject: Re: Some issue with pointers |  |
Ben Bacarisse ha scritto:
| Quote: | (1) Use C99 designated initialiser syntax:
{ .fp = myfunc }
|
This one doesn't work. I bet Dynamic C is not C99 compliant.
| Quote: | (2) Let the compiler complain about the type-mismatch (if it works):
{ myfunc }
(3) Convert to void * (again, if that is permitted):
{ (void *)myfunc }
|
These works, or at least the compiler says nothing about.
Now I have to verify that myfunc is actually assigned to fp and not to vp.
| Quote: | You don't loose anything this way. In your method, you were still going to have to initialise a void * with a function pointer which is what the above does (with C99 you can only initialise the first element of a union).
Of course, you can do it at runtime (mn_mnu.ptr.fp = myfunc;) but then you can have the menu as const.
|
Yeah, I want to declare them as constants to save code space.
Thanks again Marco / iw2nzm |
| |
| | | Marco Trapanese |  |
| Posted: Tue Jul 01, 2008 1:56 pm Post subject: Re: Some issue with pointers |  |
Marco Trapanese ha scritto:
| Quote: | Now I have to verify that myfunc is actually assigned to fp and not to vp.
|
Verified. Great! It works like a charm.
Marco / iw2nzm |
| |
| | | Ben Bacarisse |  |
| Posted: Tue Jul 01, 2008 1:59 pm Post subject: Re: Some issue with pointers |  |
Marco Trapanese <marcotrapaneseNOSPAM@gmail.com> writes:
| Quote: | Ben Bacarisse ha scritto:
(1) Use C99 designated initialiser syntax:
{ .fp = myfunc }
This one doesn't work. I bet Dynamic C is not C99 compliant.
|
Shame. This is one of the nice part of C99.
| Quote: | (2) Let the compiler complain about the type-mismatch (if it works):
{ myfunc }
(3) Convert to void * (again, if that is permitted):
{ (void *)myfunc }
These works, or at least the compiler says nothing about.
Now I have to verify that myfunc is actually assigned to fp and not to vp.
|
You do realise that they are, in effect, one and the same? You can't have both fp and vp assigned different values at the same time. That is what the union is for.
-- Ben. |
| |
| | | Marco Trapanese |  |
| Posted: Tue Jul 01, 2008 2:13 pm Post subject: Re: Some issue with pointers |  |
Ben Bacarisse ha scritto:
| Quote: | You do realise that they are, in effect, one and the same? You can't have both fp and vp assigned different values at the same time. That is what the union is for.
|
You're right again. I didn't realized that. But now I should have understood: all union items share the same address so they are "the same" thing.
Ok, I learned something new today :)
Marco / iw2nzm |
| |
| | | Keith Thompson |  |
| Posted: Tue Jul 01, 2008 2:59 pm Post subject: Re: Some issue with pointers |  |
| |  | |
Marco Trapanese <marcotrapaneseNOSPAM@gmail.com> writes:
| Quote: | Ben Bacarisse ha scritto: You do realise that they are, in effect, one and the same? You can't have both fp and vp assigned different values at the same time. That is what the union is for.
You're right again. I didn't realized that. But now I should have understood: all union items share the same address so they are "the same" thing. [...] |
Well, sort of. They're not really "the same" thing; they're different things that happen to share the same space.
Imagine that you work the day shift, and you share an office with someone who works the night shift. You're never in the office at the same time. You both have the same address, but you're two different people. And somebody who wants to visit one of you need to know what time it is to know which one of you to expect.
As for initialization, an ordinary C90-style initializer for a union simply initializes the first declared member. For example:
int main(void) { union foo { int x; char *s; };
union foo obj1 = { 42 }; /* ok, sets obj1.x to 42 */ union foo obj2 = { "hello" }; /* wrong, tries to set x to "hello" */
return 0; }
C99 lets you choose which member you want to initialize, but since you apparently want to initialize the first one anyway, you don't need that feature.
-- Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" |
| |
| Page 1 of 3 .:. Goto page 1, 2, 3 Next | |
|
|