Some issue with pointers

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Marco Trapanese

    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

    #2
    Re: Some issue with pointers

    Marco Trapanese <marcotrapanese NOSPAM@gmail.co mwrites:
    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?
    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.
    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].
    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).
    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.

    Comment

    • Marco Trapanese

      #3
      Re: Some issue with pointers

      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;
      >
      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!

      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! :)

      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.

      >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.

      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.

      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

      Comment

      • Marco Trapanese

        #4
        Re: Some issue with pointers

        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}

        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

        Comment

        • Ben Bacarisse

          #5
          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 <marcotrapanese NOSPAM@gmail.co mwrites:
          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.

          Comment

          • Marco Trapanese

            #6
            Re: Some issue with pointers

            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.

            (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 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

            Comment

            • Marco Trapanese

              #7
              Re: Some issue with pointers

              Marco Trapanese ha scritto:
              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

              Comment

              • Ben Bacarisse

                #8
                Re: Some issue with pointers

                Marco Trapanese <marcotrapanese NOSPAM@gmail.co mwrites:
                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.
                >(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.

                Comment

                • Marco Trapanese

                  #9
                  Re: Some issue with pointers

                  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.

                  Ok, I learned something new today :)

                  Marco / iw2nzm

                  Comment

                  • Keith Thompson

                    #10
                    Re: Some issue with pointers

                    Marco Trapanese <marcotrapanese NOSPAM@gmail.co mwrites:
                    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_Keit h) 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"

                    Comment

                    • Marco Trapanese

                      #11
                      Re: Some issue with pointers

                      Keith Thompson ha scritto:
                      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.
                      Got it.

                      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.
                      mmm, I guess I can't have two items in a union of the same type, can I?
                      The compiler will know what is the item I'm going to initialize if they
                      are different. In effect, it doesn't make any sense to use a union with
                      two fields of the same type.

                      Marco / iw2nzm

                      Comment

                      • Ben Bacarisse

                        #12
                        Re: Some issue with pointers

                        Marco Trapanese <marcotrapanese NOSPAM@gmail.co mwrites:
                        Keith Thompson ha scritto:
                        >
                        >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.
                        >
                        Got it.
                        >
                        >
                        >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.
                        >
                        mmm, I guess I can't have two items in a union of the same type, can I?
                        The compiler will know what is the item I'm going to initialize if
                        they are different. In effect, it doesn't make any sense to use a
                        union with two fields of the same type.
                        It doesn't work like that -- the type of the expression used to
                        initialise a union has no effect in choosing which member is
                        initialised. When a union is initialised, it is the first
                        member that is chosen unless (in C99 code) a designator is given:

                        union eg1 {
                        double d;
                        int i;
                        } example1 = { 1.2 };

                        This initialises the double, and this:

                        union eg2 {
                        int i;
                        double d;
                        } example2 = { 1.2 };

                        initialises the int (converting the 1.2 in the process). You can have
                        several members of the same type but although that would be pointless
                        it has no effect on the compiler initialises the union.

                        --
                        Ben.

                        Comment

                        • Marco Trapanese

                          #13
                          Re: Some issue with pointers

                          Ben Bacarisse ha scritto:
                          union eg1 {
                          double d;
                          int i;
                          } example1 = { 1.2 };
                          >
                          This initialises the double, and this:
                          >
                          union eg2 {
                          int i;
                          double d;
                          } example2 = { 1.2 };
                          >
                          initialises the int (converting the 1.2 in the process). You can have
                          several members of the same type but although that would be pointless
                          it has no effect on the compiler initialises the union.

                          I'm feeling a bit stupid but I don't understand the whole thing.
                          Why in my code I can initialize the function pointer that is the second
                          element?

                          Is it related to C90/C99 stuff?

                          Marco / iw2nzm

                          Comment

                          • Marco Trapanese

                            #14
                            Re: Some issue with pointers

                            Ben Bacarisse ha scritto:
                            typedef struct {
                            char *name[2];
                            int type;
                            union {
                            void *vp;
                            void (*fp)();
                            struct menu_t *items;
                            } ptr;
                            } menu_t;

                            Hello again, this time I'm trying to initialize the union with the third
                            entry, that is another menu_t struct.

                            const menu_t mn_menu = {
                            {"Main Menu", "Menu"},
                            MIT_SUBMENU,
                            {{mn_setup, mn_about}}
                            };

                            Where mn_setup and mn_about are other two const structs previously
                            defined. The compilers complains about type mismatch. I thought I was
                            able to initialize this damn unions but I was wrong.

                            It works with an array, it works with a function pointer why doesn't
                            work with a struct?

                            Marco / iw2nzm

                            Comment

                            • Keith Thompson

                              #15
                              Re: Some issue with pointers

                              Marco Trapanese <marcotrapanese NOSPAM@gmail.co mwrites:
                              Ben Bacarisse ha scritto:
                              >
                              union eg1 {
                              double d;
                              int i;
                              } example1 = { 1.2 };
                              This initialises the double, and this:
                              union eg2 {
                              int i;
                              double d;
                              } example2 = { 1.2 };
                              initialises the int (converting the 1.2 in the process). You can
                              have
                              several members of the same type but although that would be pointless
                              it has no effect on the compiler initialises the union.
                              >
                              >
                              I'm feeling a bit stupid but I don't understand the whole thing.
                              Why in my code I can initialize the function pointer that is the
                              second element?
                              >
                              Is it related to C90/C99 stuff?
                              I had to go back up the thread to see what you're talking about:

                              union {
                              void *vp;
                              void (*fp)();
                              struct menu *items;
                              } ptr;

                              This was part of a larger structure. You initialized ptr to {mypar},
                              where mypar is the name of an array of char.

                              The result of evaluating ``mypar'', of type char*, was implicitly
                              converted to void* and used to initialize ptr.vp. (This indirectly
                              assigns a value to the space occupied by ptr.fp and ptr.items, but
                              accessing those members is unsafe.)

                              Any initialization of this union, unless you use a C99 designated
                              initializer, is going to initialize ptr.vp.

                              If this doesn't match your understanding, can you post a small example
                              that illustrates the issue?

                              --
                              Keith Thompson (The_Other_Keit h) 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"

                              Comment

                              Working...