Ah've got them Function Pointer blues

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

    Ah've got them Function Pointer blues

    Folks,

    I've been playing with C programs for 25 years (not professionally -
    self-taught), and although I've used function pointers before, I've never
    got my head around them enough to be able to think my way through what I
    want to do now. I don't know why - I'm fine with most other aspects of the
    language, but my brain goes numb when I'm reading about function pointers!

    I would like to have an array of structures, something like

    struct FS
    { <function pointer>;
    <some other variables>;
    };

    My problem is that the <function pointeris of unknown type - in
    function_struct ure[2] it may be

    int func_1(int, int) {....}

    in function_struct ure[5], it may be

    void func_2(char **cpt) {....}

    etc.

    I would like to initialise the array directly, like
    struct FS function_struct ure[] = {{ ....}, {....}, ...., {....}};

    .... but I'm really shaky on what to put in those braces. I have been
    playing with it, but so far unsuccessfully.

    Is it possible? How do I declare the pointer in the structure, and how do I
    assign a pointer value to it? And when I call it, how do I pass arguments
    from the program? Could somebody give me a very simple example?

    This isn't a homework thing, by the way - I write mostly little programs
    that get used at work by colleagues. It improves my street-cred
    (geek-cred? - well, no - I've just blown that notion!).

    Incidentally, this may not be the best way to design the program, so I'd
    like to ask about that too.
    Can anybody suggest a newsgroup? (program architecture isn't really C)

    Thanks,

    MikeC


    --
    Mental decryption required to bamboozle spam robots:

    mijewen$btconne ct*com
    $ = @
    * = dot


  • Ben Bacarisse

    #2
    Re: Ah've got them Function Pointer blues

    "MikeC" <Mike.Best@btco nnect.comwrites :

    <snip>
    I would like to have an array of structures, something like
    >
    struct FS
    { <function pointer>;
    <some other variables>;
    };
    >
    My problem is that the <function pointeris of unknown type - in
    function_struct ure[2] it may be
    >
    int func_1(int, int) {....}
    >
    in function_struct ure[5], it may be
    >
    void func_2(char **cpt) {....}
    >
    etc.
    That is not a problem since a function pointer of one type can be
    converted to a function pointer of another type. The simplest is to
    pick either a generic function pointer type and use that (the type
    void (*)() is often used for this) or to pick the most common, thereby
    cutting down the number of conversions needed.

    Note that you need to convert the pointer to the right type at the
    point of call.
    I would like to initialise the array directly, like
    struct FS function_struct ure[] = {{ ....}, {....}, ...., {....}};
    Well, using the idea of a bland generic function pointer and using
    typedefs to make the syntax simple:

    typedef void function();

    The struct will the look like this:

    struct FS {
    function *fp;
    /* other data */
    };

    and you set up an array of them like this:

    struct FS function_struct ure[] = {
    {(function *)func_1, /* other data */},
    {(function *)func_2, /* other data */}
    };

    The function call is horrible, though. function_struct ure[1].fp is of
    type 'function *' and must be converted to 'void (*)(char **)' so you
    need to write:

    ((void (*)(char **))function_st ructure[1].fp)(argv);
    ... but I'm really shaky on what to put in those braces. I have been
    playing with it, but so far unsuccessfully.
    You can simplify the casts with typedefs for you common pointer types
    if you like.
    Is it possible? How do I declare the pointer in the structure, and how do I
    assign a pointer value to it? And when I call it, how do I pass arguments
    from the program? Could somebody give me a very simple example?
    --
    Ben.

    Comment

    • voidpointer

      #3
      Re: Ah've got them Function Pointer blues

      On 20 ago, 20:14, "MikeC" <Mike.B...@btco nnect.comwrote:
      Folks,
      >
      I've been playing with C programs for 25 years (not professionally -
      self-taught), and although I've used function pointers before, I've never
      got my head around them enough to be able to think my way through what I
      want to do now.  I don't know why - I'm fine with most other aspects ofthe
      language, but my brain goes numb when I'm reading about function pointers!
      >
      I would like to have an array of structures, something like
      >
      struct FS
      { <function pointer>;
         <some other variables>;
      >
      };
      >
      My problem is that the <function pointeris of unknown type - in
      function_struct ure[2] it may be
      >
      int func_1(int, int) {....}
      >
      in function_struct ure[5], it may be
      >
      void func_2(char **cpt)  {....}
      >
      etc.
      >
      I would like to initialise the array directly, like
       struct FS  function_struct ure[] = {{ ....}, {....}, ...., {....}};
      >
      ... but I'm really shaky on what to put in those braces.  I have been
      playing with it, but so far unsuccessfully.
      >
      Is it possible?  How do I declare the pointer in the structure, and howdo I
      assign a pointer value to it?  And when I call it, how do I pass arguments
      from the program?  Could somebody give me a very simple example?
      >
      This isn't a homework thing, by the way - I write mostly little programs
      that get used at work by colleagues.  It improves my street-cred
      (geek-cred? - well, no - I've just blown that notion!).
      >
      Incidentally, this may not be the best way to design the program, so I'd
      like to ask about that too.
      Can anybody suggest a newsgroup? (program architecture isn't really C)
      >
      Thanks,
      >
      MikeC
      >
      --
      Mental decryption required to bamboozle spam robots:
      >
      mijewen$btconne ct*com
      $ = @
      * = dot
      as Ben Becarisse said, do make your code more readable use the
      typedef,

      /* funcPtr is a pointer function that has two int
      as argument, and return int */
      typedef int (*funcPtr)(int, int);

      now in your structure

      struct your_struct {
      funcPtr func;
      };

      now to initialize your structure

      struct your_function t[] = {
      {&anyfunction /* with the same type of funcPtr */ },
      { /* here more declarations */ }
      };

      now to use

      (t[0].func)(argument _1, argument_2);

      a more complete example

      ------ start ------
      #include <stdio.h>

      typedef int (*funcPtr)(int, int);

      struct test {
      funcPtr func;
      int a, b;
      };

      int print_sum(int a, int b)
      {
      printf("%d\n", a + b);
      return a + b;
      }

      int main(void) {
      struct test t[] = {
      {&print_sum, 2, 2},
      {&print_sum, 5, 5}
      };

      (*(t[0].func))(t[0].a, t[0].b);
      (t[1].func)(t[1].a, t[1].b);
      /* the two ways is valid, but the second is more preferred
      and is supported since of c89 standard */
      return 0;
      }
      ------- end --------


      Comment

      • Ben Bacarisse

        #4
        Re: Ah've got them Function Pointer blues

        voidpointer <diegorocha1987 @gmail.comwrite s:
        On 20 ago, 20:14, "MikeC" <Mike.B...@btco nnect.comwrote:
        >I would like to have an array of structures, something like
        >>
        >struct FS
        >{ <function pointer>;
        >   <some other variables>;
        >>
        >};
        >>
        >My problem is that the <function pointeris of unknown type - in
        >function_struc ture[2] it may be
        >>
        >int func_1(int, int) {....}
        >>
        >in function_struct ure[5], it may be
        >>
        >void func_2(char **cpt)  {....}
        >>
        >etc.
        <snip>
        >MikeC
        >>
        >--
        >Mental decryption required to bamboozle spam robots:
        >>
        >mijewen$btconn ect*com
        >$ = @
        >* = dot
        Best not to quote sig block (unless you are commenting on them)
        as Ben Becarisse said, do make your code more readable use the
        typedef,
        >
        /* funcPtr is a pointer function that has two int
        as argument, and return int */
        typedef int (*funcPtr)(int, int);
        I prefer to not hide the pointer in the typedef. I can see you agree
        because you felt the need to reveal the pointerness in the name. "*" is
        shorter that "Ptr" and...
        now in your structure
        >
        struct your_struct {
        funcPtr func;
        function *func;

        Is just as easy to read (for someone who has had to "get" pointers).

        It is a small point (and by no means universally agreed upon) but it
        seems worth noting. It has the huge benefit that you can avoid a lot
        of the (*name)(...) syntax that seems to be the stumbling block for so
        many people.
        };
        >
        now to initialize your structure
        >
        struct your_function t[] = {
        {&anyfunction /* with the same type of funcPtr */ },
        { /* here more declarations */ }
        };
        >
        now to use
        >
        (t[0].func)(argument _1, argument_2);
        The OP was interested in there being different function types. You
        got to show the neat version!
        a more complete example
        >
        ------ start ------
        #include <stdio.h>
        >
        typedef int (*funcPtr)(int, int);
        >
        struct test {
        funcPtr func;
        int a, b;
        };
        >
        int print_sum(int a, int b)
        {
        printf("%d\n", a + b);
        return a + b;
        }
        >
        int main(void) {
        struct test t[] = {
        {&print_sum, 2, 2},
        {&print_sum, 5, 5}
        };
        >
        (*(t[0].func))(t[0].a, t[0].b);
        (t[1].func)(t[1].a, t[1].b);
        /* the two ways is valid, but the second is more preferred
        and is supported since of c89 standard */
        I prefer t[1].func(t[1].a, t[1].b); because I don't like extra
        parentheses, but that is also debatable.
        return 0;
        }
        ------- end --------
        --
        Ben.

        Comment

        • MikeC

          #5
          Re: Ah've got them Function Pointer blues

          Gentlefolk,

          You're good people. Your time and attention are very much appreciated.

          Reading through it, it all makes sense - though I still have to work it into
          operation.
          I think the problem that I have (and maybe other people have) is that if you
          have a pointer to a variable (of whatever type), and you execute

          *foo = bar

          you can easily see the mechanism of what happens. You'll laugh at the
          analogy, but to me, it's like the postman handing the value to the variable
          directly through the front door, but when it's a function pointer, the
          postman comes to the door, gets on his mobile phone, and tells somebody else
          to take the arguments around to the back door. They don't get to the
          function by the same mechanism that gets a value to a dereferenced variable.

          What I have learned, or at least had my eyes opened to from your
          instructions, is that you can make a cast to a function pointer. I never
          thought of that before, and I don't think I've read about it. Well, maybe I
          did, but my brain was numb.

          Thanks again for freely sharing your expertise.

          MikeC

          "Ben Bacarisse" <ben.usenet@bsb .me.ukwrote in message
          news:87vdxvdqk1 .fsf@bsb.me.uk. ..
          voidpointer <diegorocha1987 @gmail.comwrite s:
          >
          >On 20 ago, 20:14, "MikeC" <Mike.B...@btco nnect.comwrote:
          >>I would like to have an array of structures, something like
          >>>
          >>struct FS
          >>{ <function pointer>;
          >><some other variables>;
          >>>
          >>};
          >>>
          >>My problem is that the <function pointeris of unknown type - in
          >>function_stru cture[2] it may be
          >>>
          >>int func_1(int, int) {....}
          >>>
          >>in function_struct ure[5], it may be
          >>>
          >>void func_2(char **cpt) {....}
          >>>
          >>etc.
          <snip>
          >>MikeC
          >>>
          >>--
          >>Mental decryption required to bamboozle spam robots:
          >>>
          >>mijewen$btcon nect*com
          >>$ = @
          >>* = dot
          >
          Best not to quote sig block (unless you are commenting on them)
          >
          >as Ben Becarisse said, do make your code more readable use the
          >typedef,
          >>
          >/* funcPtr is a pointer function that has two int
          > as argument, and return int */
          >typedef int (*funcPtr)(int, int);
          >
          I prefer to not hide the pointer in the typedef. I can see you agree
          because you felt the need to reveal the pointerness in the name. "*" is
          shorter that "Ptr" and...
          >
          >now in your structure
          >>
          >struct your_struct {
          > funcPtr func;
          >
          function *func;
          >
          Is just as easy to read (for someone who has had to "get" pointers).
          >
          It is a small point (and by no means universally agreed upon) but it
          seems worth noting. It has the huge benefit that you can avoid a lot
          of the (*name)(...) syntax that seems to be the stumbling block for so
          many people.
          >
          >};
          >>
          >now to initialize your structure
          >>
          >struct your_function t[] = {
          > {&anyfunction /* with the same type of funcPtr */ },
          > { /* here more declarations */ }
          >};
          >>
          >now to use
          >>
          >(t[0].func)(argument _1, argument_2);
          >
          The OP was interested in there being different function types. You
          got to show the neat version!
          >
          >a more complete example
          >>
          >------ start ------
          >#include <stdio.h>
          >>
          >typedef int (*funcPtr)(int, int);
          >>
          >struct test {
          >funcPtr func;
          >int a, b;
          >};
          >>
          >int print_sum(int a, int b)
          >{
          >printf("%d\n ", a + b);
          >return a + b;
          >}
          >>
          >int main(void) {
          >struct test t[] = {
          >{&print_sum, 2, 2},
          >{&print_sum, 5, 5}
          >};
          >>
          >(*(t[0].func))(t[0].a, t[0].b);
          >(t[1].func)(t[1].a, t[1].b);
          >/* the two ways is valid, but the second is more preferred
          > and is supported since of c89 standard */
          >
          I prefer t[1].func(t[1].a, t[1].b); because I don't like extra
          parentheses, but that is also debatable.
          >
          >return 0;
          >}
          >------- end --------
          >
          --
          Ben.

          Comment

          • August Karlstrom

            #6
            Re: Ah've got them Function Pointer blues

            MikeC wrote:
            [...]
            I would like to have an array of structures, something like
            >
            struct FS
            { <function pointer>;
            <some other variables>;
            };
            >
            My problem is that the <function pointeris of unknown type - in
            function_struct ure[2] it may be
            >
            int func_1(int, int) {....}
            >
            in function_struct ure[5], it may be
            >
            void func_2(char **cpt) {....}
            >
            etc.
            How come the functions have different signature and what do you want to
            achieve? Please, tell us a bit more about the underlying problem.


            August

            Comment

            • MikeC

              #7
              Re: Ah've got them Function Pointer blues


              "August Karlstrom" <fusionfile@com hem.sewrote in message
              news:g8jtk7$me6 $1@aioe.org...
              MikeC wrote:
              [...]
              >I would like to have an array of structures, something like
              >>
              >struct FS
              >{ <function pointer>;
              > <some other variables>;
              >};
              >>
              >My problem is that the <function pointeris of unknown type - in
              >function_struc ture[2] it may be
              >>
              >int func_1(int, int) {....}
              >>
              >in function_struct ure[5], it may be
              >>
              >void func_2(char **cpt) {....}
              >>
              >etc.
              >
              How come the functions have different signature and what do you want to
              achieve? Please, tell us a bit more about the underlying problem.
              >
              >
              August
              Well, I would have done that in the first place, but that's to do with
              architecture, not with C, and this is a C group, and flames burn me. In my
              original post, I asked:

              "Incidental ly, this may not be the best way to design the program, so I'd
              like to ask about that too.
              Can anybody suggest a newsgroup? (program architecture isn't really C)"

              However, as you ask ...

              I haven't finished specifying the program yet - I keep having bigger and
              better ideas - but I want to write a text macro engine. It will interpret
              commands from a (text) command file, executing them on an input (read only)
              file, and producing an output file. The commands will be, for example

              copy off // don't copy anythying from the input file to the output file
              find_forward "a text string"
              move_left 6 // characters
              copy on // this causes any character scanned by the cursor to be copied to
              the output file
              loop 6 // times
              { <more commands>
              }
              etc....

              .... you get the idea.
              I wanted to run through the command (program) file and compile it into a
              forth-like stack (yes, I'm a dinosaur), with each stack element being a
              structure, which contains, among other things, a pointer to the function
              that will execute the command. The commands do different things, so they
              have different signatures, hence my question.

              Among all the ways of solving this problem (the architecture problem), I'm
              sure people who have spent a life in preofeesional programming will know of
              much better methods, and probably be able to pull in other
              packages/libraries that would do a lot of the work - but I don't know about
              those. I usually write programs from scratch, and write everything.

              Last night, I wrote char *stristr(char *str) because it isn't in the
              library - though I'm sure it's somewhere (though I wouldn't know where to
              look). I'm rather pleased with it! :-)

              Regards,

              MikeC



              Comment

              • Ben Bacarisse

                #8
                Re: Ah've got them Function Pointer blues

                "MikeC" <Mike.Best@btco nnect.comwrites :
                "August Karlstrom" <fusionfile@com hem.sewrote in message
                <snip>
                >How come the functions have different signature and what do you want to
                >achieve? Please, tell us a bit more about the underlying problem.
                <snip>
                However, as you ask ...
                >
                I haven't finished specifying the program yet - I keep having bigger and
                better ideas - but I want to write a text macro engine. It will interpret
                commands from a (text) command file, executing them on an input (read only)
                file, and producing an output file. The commands will be, for example
                >
                copy off // don't copy anythying from the input file to the output file
                find_forward "a text string"
                move_left 6 // characters
                copy on // this causes any character scanned by the cursor to be copied to
                the output file
                loop 6 // times
                { <more commands>
                }
                etc....
                >
                ... you get the idea.
                I wanted to run through the command (program) file and compile it into a
                forth-like stack (yes, I'm a dinosaur), with each stack element being a
                structure, which contains, among other things, a pointer to the function
                that will execute the command. The commands do different things, so they
                have different signatures, hence my question.
                This does not follow automatically from what you have said. I have
                done similar things and there is no reason why the functions /need/ to
                have different types. One way to look at it is that the functions all
                modify the state of a "text copying virtual machine". I.e. each one
                takes a pointer to a structure that describes that program's state:
                the file positions, variable bindings, stack and so on.

                While there is a cost here (all the state get piled into one place)
                the payoff is that you don't need a big switch effectively doing
                run-time type checking. Remember I said that at the time of the call
                the function pointer must be cast to the correct type? You end up
                with a messy if-then-else chain (or a switch) resolving the correct
                way to call each of the various kinds. It is well worth trying to get
                them all to be the same.

                --
                Ben.

                Comment

                • MikeC

                  #9
                  Re: Ah've got them Function Pointer blues


                  "Ben Bacarisse" <ben.usenet@bsb .me.ukwrote in message
                  news:87y72p9lvz .fsf@bsb.me.uk. ..
                  "MikeC" <Mike.Best@btco nnect.comwrites :
                  >
                  > The commands will be, for example
                  >>
                  >copy off // don't copy anythying from the input file to the output file
                  >find_forward "a text string"
                  >move_left 6 // characters
                  >copy on // this causes any character scanned by the cursor to be copied
                  >to
                  >the output file
                  >loop 6 // times
                  >{ <more commands>
                  >}
                  >etc....
                  >>
                  >... you get the idea.
                  >I wanted to run through the command (program) file and compile it into a
                  >forth-like stack, with each stack element being a
                  >structure, which contains, among other things, a pointer to the function
                  >that will execute the command.
                  >
                  This does not follow automatically from what you have said. I have
                  done similar things and there is no reason why the functions /need/ to
                  have different types. One way to look at it is that the functions all
                  modify the state of a "text copying virtual machine". I.e. each one
                  takes a pointer to a structure that describes that program's state:
                  the file positions, variable bindings, stack and so on.
                  >
                  While there is a cost here (all the state get piled into one place)
                  the payoff is that you don't need a big switch effectively doing
                  run-time type checking. Remember I said that at the time of the call
                  the function pointer must be cast to the correct type? You end up
                  with a messy if-then-else chain (or a switch) resolving the correct
                  way to call each of the various kinds. It is well worth trying to get
                  them all to be the same.
                  >
                  --
                  Ben.
                  Thanks Ben, but I'm not sure I understand what you are thinking about.
                  The instructions above are a small sub-set of the instructions that will be
                  available.

                  find_forward "a text string" takes a string argument.
                  move_left 6 takes a decimal integer.
                  add var_2 14 takes a variable and a constant

                  I will have variables which I can add together, subtract, do simple
                  arithmetic, etc.

                  It seems to me all the functions are different. I can't envisage what you
                  have in mind - but then, you probably have a wealth of experince and
                  shoulder-rubbing with other programmers. I've been doing it for a long
                  time, but I have never known anybody else with an interest in it.

                  I can have a state machine to handle the text, yes, but it will have quite a
                  lot of buttons to push, and sometimes, two or three buttons in combination
                  to get it to the next state. Actually, the concept of a state machine had
                  not occurred to me. Thanks - I'll give that some thought.

                  What I have in mind would require a degree of pre-compilation, which would
                  require a switch, but I was planning to use the function pointers to replace
                  the switch as described in http://www.newty.de/fpt/intro.html. At run-time,
                  it would use the concepts of the Forth virtual machine, which is a simple,
                  reverse polish, stack-based machine. Very quick at run time for a
                  semi-interpreted language.

                  .... but we're getting quite off-topic. Is there an architecture group that
                  would be more appropriate?

                  Thanks,

                  MikeC


                  Comment

                  • Ben Bacarisse

                    #10
                    Re: Ah've got them Function Pointer blues

                    "MikeC" <Mike.Best@btco nnect.comwrites :
                    "Ben Bacarisse" <ben.usenet@bsb .me.ukwrote in message
                    news:87y72p9lvz .fsf@bsb.me.uk. ..
                    >"MikeC" <Mike.Best@btco nnect.comwrites :
                    >>
                    >> The commands will be, for example
                    >>>
                    >>copy off // don't copy anythying from the input file to the output file
                    >>find_forwar d "a text string"
                    >>move_left 6 // characters
                    >>copy on // this causes any character scanned by the cursor to be copied
                    >>to
                    >>the output file
                    >>loop 6 // times
                    >>{ <more commands>
                    >>}
                    >>etc....
                    >>>
                    >>... you get the idea.
                    >>I wanted to run through the command (program) file and compile it into a
                    >>forth-like stack, with each stack element being a
                    >>structure, which contains, among other things, a pointer to the function
                    >>that will execute the command.
                    >>
                    >This does not follow automatically from what you have said. I have
                    >done similar things and there is no reason why the functions /need/ to
                    >have different types. One way to look at it is that the functions all
                    >modify the state of a "text copying virtual machine". I.e. each one
                    >takes a pointer to a structure that describes that program's state:
                    >the file positions, variable bindings, stack and so on.
                    >>
                    >While there is a cost here (all the state get piled into one place)
                    >the payoff is that you don't need a big switch effectively doing
                    >run-time type checking. Remember I said that at the time of the call
                    >the function pointer must be cast to the correct type? You end up
                    >with a messy if-then-else chain (or a switch) resolving the correct
                    >way to call each of the various kinds. It is well worth trying to get
                    >them all to be the same.
                    >>
                    >--
                    >Ben.
                    Best not to quote sig blocks.
                    Thanks Ben, but I'm not sure I understand what you are thinking about.
                    The instructions above are a small sub-set of the instructions that will be
                    available.
                    >
                    find_forward "a text string" takes a string argument.
                    move_left 6 takes a decimal integer.
                    add var_2 14 takes a variable and a constant
                    >
                    I will have variables which I can add together, subtract, do simple
                    arithmetic, etc.
                    >
                    It seems to me all the functions are different.
                    If you start to generalise, I'd bet they merge into a common type.
                    For example, why have only string literals? If you can:

                    set myvar next(3)
                    find_forward myvar

                    To pick put "abc" and skip to the next "abc". Or

                    set myvar next(3)
                    find_forward myvar+myvar

                    to skip to "abcabc" then suddenly find_forward needs an "expression "
                    type object just like everything else. And if some operation needs
                    more than one piece of data, it can be solved by have a way to
                    represent "tuples" like (42, "a string") as a single value.

                    Now, you may has a design the does not this generality, so by all
                    means use separate types, but as you extend the functions of your
                    program, I bet you will find the types start to come together. This
                    is a case where generalising early, can help.

                    I have just finished the message I noted that you are planning on
                    something like Forth. That makes my plan all the better, but I will
                    leave this general idea here anyway.
                    I can't envisage what you
                    have in mind - but then, you probably have a wealth of experince and
                    shoulder-rubbing with other programmers. I've been doing it for a long
                    time, but I have never known anybody else with an interest in it.
                    That is a shame. It really helps to talk over designs.
                    comp.programmin g is good place for general discussions.
                    I can have a state machine to handle the text, yes, but it will have quite a
                    lot of buttons to push, and sometimes, two or three buttons in combination
                    to get it to the next state. Actually, the concept of a state machine had
                    not occurred to me. Thanks - I'll give that some thought.
                    >
                    What I have in mind would require a degree of pre-compilation, which would
                    require a switch, but I was planning to use the function pointers to replace
                    the switch as described in http://www.newty.de/fpt/intro.html. At run-time,
                    it would use the concepts of the Forth virtual machine, which is a simple,
                    reverse polish, stack-based machine. Very quick at run time for a
                    semi-interpreted language.
                    If you are going forth-ish then I think you won't need separate types
                    at all. All forth opcodes act on "the stack" -- they all have the
                    same type:

                    find_forward: pop "thing" from stack, scan for it.
                    move_left: pop "thing" from stack and treat it as a number f
                    places to move
                    add: pop two things. One is treated as a variable name (or
                    reference) the second is a value.

                    You will need a way to represent stack values, but all operations just
                    need the internal scanning state and the stack to do their work.
                    ... but we're getting quite off-topic. Is there an architecture group that
                    would be more appropriate?
                    comp.programmin g is the best I can think of.

                    --
                    Ben.

                    Comment

                    • MikeC

                      #11
                      Re: Ah've got them Function Pointer blues

                      "MikeC" <Mike.Best@btco nnect.comwrote in message
                      news:jcqdnYojVd ffODHVnZ2dnUVZ8 tDinZ2d@bt.com. ..
                      Folks,
                      >
                      Well, Folks,

                      Following advice/inspiration given in this thread, I have spent some time
                      playing with function pointers, but I still haven't been able to make them
                      work the way I want them to.
                      Please see my comments in the last few lines of main().

                      void func_a(char *str)
                      // stupid function - increments each character in the string
                      { char *pt = str;
                      while(*pt != '\0')
                      { *pt = (*pt)++ & 0xff;
                      pt++;
                      }
                      }

                      int func_b(void)
                      // returns number of ticks since midnight
                      { return rawclock();
                      }

                      char *func_c(char *str)
                      // returns a pointer to the mid-point of the string
                      { char *pt = str;
                      while(*pt) pt++;
                      return str + (pt - str)/2;
                      }

                      int mult_ab(int a, int b)
                      // returns the product of two numbers
                      { return (a * b);
                      }

                      main(int argc, char *argv[])
                      { int i1, i2;
                      char str[] = "1234567890abcd efgh";
                      char *pt;
                      void (*fpv)();
                      int (*fpi)();
                      char *(*fpc)();

                      // the following work fine
                      fpv = func_a;
                      fpv(str); // this modifies the string as expected

                      fpi = (void*)func_a;
                      fpi(str); // this also compiles and works.

                      fpi = func_b; // this works too, but func_b expects to return an int,
                      i1 = fpi(); // and fpi is an int pointer, so I would /expect/ it to work

                      fpi = mult_ab; // this also works - also expected, as fpi returns an int
                      i2 = fpi(3, 5);

                      fpc = func_c; // this assignment compiles
                      fpi = fpc; // this one gives a compile warning. No luck in casting it.
                      pt = (char *)fpi(str); // but this line shows that it worked.
                      //fpi = ((int*)())fpc; // this cast fails compilation
                      //fpi = (int)(*)())fpc; // ... as does this one. Tried various fanciful
                      // and desperate things without success
                      // I have also been unable to cast the void function pointer, fpv, to
                      point func_b or func_c,
                      // and to return an int or an char*
                      }

                      I'm sinking!
                      (Don't ask what I'm sinking about - I've heard that one!)

                      MikeC.
                      mijewen$btconne ct*com
                      $ = @
                      * = dot There are 10 kinds of people in the world - those who understand
                      binary, and those who don't.


                      Comment

                      • Richard Heathfield

                        #12
                        Re: Ah've got them Function Pointer blues

                        Just as an introduction to this article, my implementation' s diagnostics
                        for posted code (after C99 comments removed):

                        foo.c:2: warning: no previous prototype for `func_a'
                        foo.c:10: warning: no previous prototype for `func_b'
                        foo.c: In function `func_b':
                        foo.c:10: warning: implicit declaration of function `rawclock'
                        foo.c: At top level:
                        foo.c:14: warning: no previous prototype for `func_c'
                        foo.c:20: warning: no previous prototype for `mult_ab'
                        foo.c:24: warning: return-type defaults to `int'
                        foo.c: In function `main':
                        foo.c:27: warning: function declaration isn't a prototype
                        foo.c:28: warning: function declaration isn't a prototype
                        foo.c:29: warning: function declaration isn't a prototype
                        foo.c:34: warning: ANSI forbids assignment between function pointer and
                        `void *'
                        foo.c:44: warning: assignment from incompatible pointer type
                        foo.c:45: warning: cast does not match function type
                        foo.c:46: parse error before `)'
                        foo.c:47: parse error before `)'
                        foo.c:47: parse error before `)'
                        foo.c:23: warning: unused parameter `argc'
                        foo.c:23: warning: unused parameter `argv'
                        foo.c:48: warning: control reaches end of non-void function
                        make: *** [foo.o] Error 1

                        Comments on code follow:

                        MikeC said:

                        <snip>
                        void func_a(char *str)
                        // stupid function - increments each character in the string
                        { char *pt = str;
                        while(*pt != '\0')
                        { *pt = (*pt)++ & 0xff;
                        The behaviour of the code is undefined from this point. The problem is that
                        you are modifying *pt twice between consecutive sequence points.

                        <snip>
                        // the following work fine
                        fpv = func_a;
                        fpv(str); // this modifies the string as expected
                        Unlucky. If it had not done so (and there's no reason why it should and no
                        reason why it shouldn't), you might have been motivated to investigate.
                        fpi = (void*)func_a;
                        The cast is unwise, since C doesn't provide any guaranteed conversion
                        between function pointers and void *. You could, however, have used a cast
                        to (int(*)()) - although I can't help wondering why you would want to -
                        why not just use a function pointer of the proper type in the first place?
                        fpi(str); // this also compiles and works.
                        >
                        fpi = func_b; // this works too, but func_b expects to return an int,
                        i1 = fpi(); // and fpi is an int pointer, so I would /expect/ it to
                        work
                        No, fpi is not an int pointer. fpi is a pointer to a function that returns
                        int.
                        fpi = mult_ab; // this also works - also expected, as fpi returns an
                        int i2 = fpi(3, 5);
                        My newsreader has, in this reply, wrapped the word 'int' to the start of
                        the next line. If you'd used /* comments */ that wouldn't have mattered.
                        Well, it doesn't really matter now either, since we both know what you
                        mean - but bear in mind that // comments are susceptible to being broken
                        by tools that format text as part of their job.

                        Back to C: fpi doesn't return anything, actually. It's a pointer, not a
                        function. It might /point/ to a function, but it is not itself a function.
                        fpc = func_c; // this assignment compiles
                        As one would expect.
                        fpi = fpc; // this one gives a compile warning. No luck in casting
                        it.
                        Why would you want to do that assignment in the first place? But if you
                        must cast (and casts help broken programs in much the same way that they
                        help broken legs - unfortunately, programs won't heal themselves like legs
                        do), do it like this: fpi = (int (*)())fpc;
                        pt = (char *)fpi(str); // but this line shows that it worked.
                        Oh dear. Yes, sometimes if you hit a square peg hard enough, it *will* fit
                        in the round hole.
                        //fpi = ((int*)())fpc; // this cast fails compilation
                        Yes, I'm not surprised. You're casting to a function type, not a function
                        pointer type, and that isn't ever going to work.
                        //fpi = (int)(*)())fpc; // ... as does this one. Tried various fanciful
                        // and desperate things without success
                        Count the ( parentheses in that line. Now count the ) parentheses.
                        // I have also been unable to cast the void function pointer, fpv, to
                        point func_b or func_c,
                        // and to return an int or an char*
                        I am at a loss to understand why you would want to.

                        --
                        Richard Heathfield <http://www.cpax.org.uk >
                        Email: -http://www. +rjh@
                        Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
                        "Usenet is a strange place" - dmr 29 July 1999

                        Comment

                        • MikeC

                          #13
                          Re: Ah've got them Function Pointer blues


                          "Richard Heathfield" <rjh@see.sig.in validwrote in message
                          news:hsCdneF2od 4RoSrVRVnyvwA@b t.com...
                          Just as an introduction to this article, my implementation' s diagnostics
                          <snip>
                          Thanks for your help, Richard. I was rather hoping for help from Ben
                          Bacarisse, as he had answered several of the preceeding points, and knew the
                          history and thread of this question. Even without reading through the
                          preamble of questions, however, some of the things you said are very
                          helpful.
                          >
                          >void func_a(char *str)
                          >// stupid function - increments each character in the string
                          >{ char *pt = str;
                          > while(*pt != '\0')
                          > { *pt = (*pt)++ & 0xff;
                          >
                          The behaviour of the code is undefined from this point. The problem is
                          that
                          you are modifying *pt twice between consecutive sequence points.
                          Yes, it could well be that it's untidy C, but it was just a quick lashup of
                          a function that took an argument, and returned none.
                          It wasn't to use in anything more than this example. It's possible it would
                          have not had the desired outcome under a different compiler, but it worked
                          on mine. The question I was asking was, in any case, not to do with making
                          my program work, but with understanding how to use function pointers. My
                          compiler is not on the machine I'm using at the moment, so stuff like
                          mis-matching parentheses is just due to a typo in transferring the info.
                          <snip>
                          >
                          >// the following work fine
                          > fpv = func_a;
                          > fpv(str); // this modifies the string as expected
                          >
                          Unlucky. If it had not done so (and there's no reason why it should and no
                          reason why it shouldn't), you might have been motivated to investigate.
                          >
                          Because there was no cast? Should I have used
                          fpv = (void(*)())func _a; //?
                          > fpi = (void*)func_a;
                          >
                          The cast is unwise, since C doesn't provide any guaranteed conversion
                          between function pointers and void *. You could, however, have used a cast
                          to (int(*)()) - although I can't help wondering why you would want to -
                          why not just use a function pointer of the proper type in the first place?
                          Ah, well that was my original question. I want to have an array of function
                          pointers, then
                          have them point to functions of different types, so
                          func[0] points to int aaa(int, char*)
                          func[1] points to void bbb(char *)
                          func[2] points to char *ccc(char *, struct KKK *kkk)
                          etc.

                          In reality, this will not be an array of pointers, but an array of
                          structures, in which each structure will contain a function pointer and
                          other variables.
                          It's explained in the previous parts of this thread.
                          My problem is that I'm (clearly!) struggling to understand function
                          pointers.

                          To bring my question down to the simplest form, if I have a function

                          int return_42(void)
                          { return 42;
                          }

                          then I declare a function pointer...

                          int main()
                          { void (*fpv)();
                          int i;

                          fpv = ????
                          i = <cast>fpv;
                          }

                          My question is this - how do I make fpv point to the function return_42, and
                          how do I induce it to assign the return value to i?

                          If I can understand that, I'm sure I can resolve the rest of my problem.

                          Many thanks,
                          MikeC
                          --
                          Richard Heathfield <http://www.cpax.org.uk >
                          Email: -http://www. +rjh@
                          Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
                          "Usenet is a strange place" - dmr 29 July 1999

                          Comment

                          • pete

                            #14
                            Re: Ah've got them Function Pointer blues

                            MikeC wrote:
                            Folks,
                            >
                            I've been playing with C programs for 25 years (not professionally -
                            self-taught), and although I've used function pointers before, I've never
                            got my head around them enough to be able to think my way through what I
                            want to do now.
                            I've seen arrays of function pointers
                            to the same type of functions used,
                            when one of a bunch of functions is selected according
                            to which interrupt just occured.

                            When I compare sorting functions,
                            I use an array of structures containing
                            function pointers to same type of sorting functions,
                            to test them sequentially in a loop.




                            But I'm unfamiliar with the use of
                            various types of function pointers
                            in the same part of a program.

                            --
                            pete

                            Comment

                            • Keith Thompson

                              #15
                              Re: Ah've got them Function Pointer blues

                              "MikeC" <Mike.Best@btco nnect.comwrites :
                              [...]
                              To bring my question down to the simplest form, if I have a function
                              >
                              int return_42(void)
                              { return 42;
                              }
                              >
                              then I declare a function pointer...
                              >
                              int main()
                              { void (*fpv)();
                              int i;
                              >
                              fpv = ????
                              i = <cast>fpv;
                              }
                              >
                              My question is this - how do I make fpv point to the function return_42, and
                              how do I induce it to assign the return value to i?
                              Use prototypes consistently. Empty parentheses in a function
                              declaration mean that the function has an unspecified number and
                              type(s) of parameters. <OT>It's different in C++.</OT To declare
                              that a function has no parameters, use "(void)".

                              You can make fpv (a pointer to function returning void) point to
                              return_42 (a function returning int), but you cannot make an indirect
                              call using the value of fpv, because the types don't match. The
                              behavior of such a call is undefined.

                              Things to remember:

                              You can convert between any pointer-to-function type and any other
                              pointer-to-function type. Such conversions always require a cast;
                              they're never done implicitly.

                              For object pointers, void* is a generic pointer type. For function
                              pointers, since they're *all* freely convertible, you can use any
                              function pointer type you like as a generic type. It's probably best
                              to use the simplest such type, ``void (*)(void)''.

                              When you call a function via a pointer-to-function, you must use a
                              pointer-to-function whose target type matches the type of the actual
                              function you're calling. The compiler won't check this for you, so
                              it's easy to get this wrong and invoke undefined behavior. For
                              example, if you call a function that returns an int via a pointer to a
                              function returning void, the code for the call will assume that the
                              function returns no value. Arbitrarily bad things can happen. If
                              you're particularly unlucky, it will appear to work, making it harder
                              to detect the bug.

                              Here's an example of the right way to do it. I use typedefs to make
                              the code easier.

                              #include <stdio.h>

                              /*
                              * Note that we can't use these typedefs directly; you
                              * can't declare a function object. But we can declare
                              * objects that are pointers to functions. I could
                              * reasonably have declared typedefs for the pointer types,
                              * but I dislike hiding pointers behind typedefs.
                              *
                              * "function_retur ning_void" might better have been called
                              * "generic_functi on".
                              */
                              typedef int (function_retur ning_int) (void);
                              typedef void(function_r eturning_void)( void);

                              int return_42(void)
                              {
                              return 42;
                              }

                              int main(void)
                              {
                              /*
                              * Declare fpv as a pointer to a function_return ing_void.
                              */
                              function_return ing_void *fpv;

                              int i;

                              /*
                              * return_42, as an expression, is a pointer to a
                              * function_return ing_int. fpv is of type pointer to
                              * function_return ing_void. Since there's no implicit
                              * conversion, we need to use a cast.
                              */
                              fpv = (function_retur ning_void *)return_42;

                              /*
                              * Now we can't make a function call using the value
                              * of fpv directly, because the types don't match.
                              * The behavior of such a call would be undefined.
                              * So we take the value of fpv, which is a pointer to
                              * function_return ing_void, and convert it *back* to a
                              * pointer to function_return ing_int. We can now call
                              * return_42() indirectly through this pointer value,
                              * which is now of the correct type.
                              */
                              i = ((function_retu rning_int *)fpv)();

                              /*
                              * Output: "i = 42"
                              */
                              printf("i = %d\n", i);

                              return 0;
                              }

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