Thread: Passing a function pointer in an argument that can have different return values

  1. #1
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92

    Passing a function pointer in an argument that can have different return values

    Two of the functions I am writing (Next_Float and Next_Integer) are very similar except for the actual conversion line. Is there a way that I can make a Next_Number function take a function pointer to the corresponding conversion routine and put the converted number to a void pointer?

    Only difference:
    Code:
    /* Code in Next_Float */
    *Target = atof(&Parser->Buffer[Float_Start]);
    /* Code in Next_Integer */
    *Target = atoi(&Parser->Buffer[Integer_Start]);
    /* Desired function */
      int Next_Number(
        Struct_Parser *Parser,
        void          *Target,
        ?????
      );
    Next_Float:
    Code:
      #define IS_CHARACTER(c)       (c>' ')
      #define IS_ESCAPE(c)          (c<'\t'||(c<' '&&c>'\t')) /* Tab is not considered an escape character */
      #define IS_WHITESPACE(c)      (c==' '||c=='\t')
      #define IS_DIGIT(c)           (c>='0'&&c<='9')
      #define IS_DIGIT_SIGN(c)      (c=='-'||c=='+')
      #define IS_DIGIT_SYMBOL(c)    (c=='-'||c=='.'||c=='+')
      #define IS_POSSIBLE_NUMBER(c) (IS_DIGIT(c)||IS_DIGIT_SYMBOL(c))
                                                                                                                                                       /*
    ---------------------------------------------------------------------------------------------------------------------------------------------------[]
                                                                                                                                                       */
      int Next_Float(
        Struct_Parser *Parser,
        float         *Target
      ){
        /* Indexes of the buffer where the number starts and ends */
        int Float_Start;
        
        /* Used by buffer for swaping values and storing a decimal count in the buffer check */
        char Temp = 0;
        
        /* Reset Skipped_Lines */
        Parser->Skipped_Lines = 0;
        Skip_Whitespace(Parser);
        
        /* If we are at the end of the line get the next */
        if(IS_ESCAPE(Parser->Buffer[Parser->Buffer_Index]) && !Fetch_Clear_Line(Parser))
          return FAILURE;
        
        /* Set the float starting position */
        Float_Start = Parser->Buffer_Index;
        
        /* Fetch characters from input that are valid digits or digit symbols */
        for(;IS_POSSIBLE_NUMBER(Parser->Buffer[Parser->Buffer_Index]);Parser->Buffer_Index++);
          
        /* Test for non-valid digit-symbol combinations */
        switch(Parser->Buffer_Index - 1 - Float_Start){
        
          /* '' */
          case -1:
            return FAILURE;
          
          /* '+', '-', '.' */
          case 0:
            if(IS_DIGIT_SYMBOL(Parser->Buffer[Float_Start]))
              return FAILURE;
            break;
          
          /* '+X', '-X', '.X', 'X+', 'X-', 'X.' */
          case 1:
            if(IS_DIGIT_SYMBOL(Parser->Buffer[Float_Start]) && IS_DIGIT_SYMBOL(Parser->Buffer[Float_Start + 1]))
              return FAILURE;
            break;
          
          /* Any other combination */
          default: 
          
            /* Loop through the buffer section that contains the possible float */
            for(int i = Float_Start;i < Parser->Buffer_Index;i++){
            
              /* Testing for non-valid digit-symbol combinations (where 'X' is a digit): 'X..', 'X+', 'X-' */
              if(Temp > 1 || (i != Float_Start && IS_DIGIT_SIGN(Parser->Buffer[i])))
                return FAILURE;
                
              /* Increment the decimal count if one is found */
              if(Parser->Buffer[i] == '.')
                Temp++;
            }
        }
        
        /* Null terminate the buffer passed the end of the float (preserving its
           previous value in Temp */
        Temp = Parser->Buffer[Parser->Buffer_Index];
        Parser->Buffer[Parser->Buffer_Index] = '\0';
        
        /* Convert the float within the buffer then restore the buffer and return */
        *Target = atof(&Parser->Buffer[Float_Start]);
        Parser->Buffer[Parser->Buffer_Index] = Temp;
        return SUCCESS;
      }
                                                                                                                                                       /*
    ---------------------------------------------------------------------------------------------------------------------------------------------------[]
    Last edited by 127.0.0.1; 05-23-2011 at 12:56 PM.

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    If you want to use those two function pointers as options for the same variable, then it'd be really handy if you could make them of the same type. You'd have to change the prototype to void* in that case.

  3. #3
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    If you want to use those two function pointers as options for the same variable, then it'd be really handy if you could make them of the same type. You'd have to change the prototype to void* in that case.
    The issue is I need to pass Next_Number a pointer to a conversion function which has an unknown return type. The purpose of this is to not just quickly be able to create a Next_Float and Next_Integer, but also create other functions like Next_Long, Next_Double etc.. I don't want to restrict myself to just 2 options.

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by 127.0.0.1 View Post
    The issue is I need to pass Next_Number a pointer to a conversion function which has an unknown return type. The purpose of this is to not just quickly be able to create a Next_Float and Next_Integer, but also create other functions like Next_Long, Next_Double etc.. I don't want to restrict myself to just 2 options.
    So replace the word "two" in my reply with "however-many-you-want". It doesn't change anything: all the prototypes need to be the same.

  5. #5
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    So replace the word "two" in my reply with "however-many-you-want". It doesn't change anything: all the prototypes need to be the same.
    Sorry, I misunderstood your original reply -- I get it now. Thanks for the help

  6. #6
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    Why don't you just return a tagged union?
    Code:
    struct token {
       int type;
       union {
          int i_value;
          float f_value;
          char *str_value;
          ....
       } Value;
    };

  7. #7
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Quote Originally Posted by Bayint Naung View Post
    Why don't you just return a tagged union?
    Code:
    struct token {
       int type;
       union {
          int i_value;
          float f_value;
          char *str_value;
          ....
       } Value;
    };
    When the function pointer is passed (as a void pointer) to Next_Number, I need to typecast the void pointer back into a function (that could return any value) and put that value in the memory area pointed to by the Target void pointer. The problem I am having now is how exactly I would preform such a typecast (I have spent hours searching on google without finding anything). How would using a union avoid this problem (sorry if I am misunderstanding)?

    Code:
    int Next_Number(
      Struct_Parser *Parser,
      void          *Target,
      void          *Conversion_Function 
    ){
      ...
      *Target = (????I don't know how to typecast this?????)Conversion_Function(&Parser->Buffer[Integer_Start]);
      ...
      return SUCCESS;
    }
    Last edited by 127.0.0.1; 05-23-2011 at 09:11 PM.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I suggest something along these lines:
    Code:
    int Next_Number(Struct_Parser *Parser, void *Target, void (*Convert)(void *To, const void *From)) {
        /* ... */
        Convert(Target, &Parser->Buffer[Float_Start]);
        /* ... */
    }
    
    void ConvertFloat(void *To, const void *From) {
        *(float*)To = atof((const char*)From);
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    I suggest something along these lines:
    So essentially, I would be creating a wrapper for the conversion functions that can be passed as a standardized parameter instead of a void pointer -- there would be two functions for every new number type (i.e Convert_X, Next_X), is this correct?

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    No, there would only be one Next_Number function, which is the whole point. You do need a Convert_X wrapper for each type X.

    Incidentally, if I remember correctly, function pointers are not convertible to/from void*.

    You might also want to consider using normal camelCase convention instead of also using underscores as separators. Of course, this is just subjective style.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    I really appreciate the help you are giving me.

    You might also want to consider using normal camelCase convention instead of also using underscores as separators. Of course, this is just subjective style.
    Pascal habits are hard to beat .

    No, there would only be one Next_Number function, which is the whole point. You do need a Convert_X wrapper for each type X.
    Would I call Next_Number like this?
    Code:
      Next_Number(Parser, &Target, &Convert_Float);

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by 127.0.0.1
    Would I call Next_Number like this?
    Possibly, though personally I would pass Convert_Float instead of &Convert_Float, but again it is a matter of style since the result is the same.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Awesome, I've got it working. This solution is exactly what I was looking for.

    Thanks again for the help lazerlight

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. String Argument and Return Values From DLL
    By C0D3BR3AK in forum Windows Programming
    Replies: 0
    Last Post: 04-28-2011, 11:50 AM
  2. Replies: 5
    Last Post: 03-06-2011, 11:57 AM
  3. Problem with Pointer as return Argument
    By gregorsart in forum C Programming
    Replies: 2
    Last Post: 05-16-2009, 08:35 AM
  4. Passing Argument-Incompatale Pointer Error
    By OxKing033 in forum C Programming
    Replies: 3
    Last Post: 02-27-2008, 10:43 PM
  5. passing pointer argument
    By timhxf in forum C Programming
    Replies: 8
    Last Post: 01-08-2007, 10:38 AM