4

I'm running in a little issue here, I've got this function pointer :

typedef void* (* funcPointer)(const void *in, int ilen, void *out, int *olen)

And this function

void* foo1(const void *in, int ilen, void *out, int *olen)
{
   if(CONST_VALUE_1 > iLen)
      //do something
   else
      //do something else
   return whatever;
}

Somewhere in the code

// ...
funcPointer fpointer = foo1;
if(someArgument > SOME_OTHER_CONSTANT)
   // where foo2 is the same as foo1 except that it uses CONST_VALUE_2
   fpointer = foo2; 
bar( someVariable, anotherVariable, fpointer);
// ...

As you can see, there is a CONST_VALUE_X in the body of this function. I would like to be able to remove the constant and use a fifth argument instead. Since I can't modify the signature, I was wondering if there was something to do or copy-paste the function with every possible constant value...

Thank you

ALOToverflow
  • 2,679
  • 5
  • 36
  • 70
  • Do you have control over any of the values being passed into the callback function? – TurqMage May 19 '11 at 17:39
  • Can you wrap it? Why don't you create a base function that takes the 5th argument, and then call it passing CONST_VALUE_X from the functions that respect your signature? – salezica May 19 '11 at 17:41
  • @TurqMage No, I don't have any control over the bar function – ALOToverflow May 19 '11 at 17:43
  • @Santiago Lezica can you explain yourself? I'm not quite sure I understand what you want to do. – ALOToverflow May 19 '11 at 17:44
  • 1
    Perhaps this currying implementation in C could give some clues: http://stackoverflow.com/questions/1023261/is-there-a-way-to-do-currying-in-c – csl May 19 '11 at 18:01
  • 1
    Sounds like you can modify `foo1`, but not its signature (because it has to be called through the function pointer by `bar`, and you can't change `bar`). Is that correct? If so, then you should probably define a function `foo` with an extra parameter, then have `foo1` call it with `CONST_VALUE_1` and `foo2` call it with `CONST_VALUE_2`. That's pretty much the best you can do without some form of closures or partial function application, which C lacks. – Steve Jessop May 19 '11 at 18:14

3 Answers3

1

If you can't modify the function signature, then as you say, you won't have a fifth argument!

I see three options:

  1. I guess you could shoehorn it into one of the other void * arguments (e.g. define a struct that contains the original value for in, and the "constant" value, and then pass this in as in).

  2. Set a global variable before calling the function. This is a bad idea.

  3. You could write this function as a macro, to avoid the copy-and-paste maintenance nightmare. This is a bad idea.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • Yes, that's what I was thinking about, but I was hoping a better and cleaner solution. – ALOToverflow May 19 '11 at 17:42
  • 2
    @Francis: I'm not sure what sort of solution you're expecting! The best and cleanest solution is to modify the signature. If you can't do that, you're left with messy solutions such as the above. – Oliver Charlesworth May 19 '11 at 17:44
  • Option #1 is the best bet. The C language doesn't have the high-level functionality you want, so you have to invent it yourself. The languages that let you do what you want are probably doing #1 "under the hood" anyway, and it's far cleaner than preprocessor macros or global variables. – Nathan Strong May 24 '11 at 01:05
0

You could replace the constant with something that the caller can temporarily change (like a global variable).

For example:

int oldLenghtLimit = LengthLimit;
... call the function ...
LengthLimit = oldLengthLimit;

And, in the function:

void* foo1(const void *in, int ilen, void *out, int *olen)
{
  if(LengthLimit > iLen)
    //do something
  else
    //do something else
  return whatever;
}
Lindydancer
  • 25,428
  • 4
  • 49
  • 68
  • Of course, that only works as long as we know the caller follows that convention. – csl May 19 '11 at 18:42
  • Not really, as the original valus is restored after the call, old code will still work (under the assumption that `LengthLimit` is initialized to `CONST_VALUE_1`). – Lindydancer May 19 '11 at 19:07
  • What I mean is that, if you hand out five function pointers to somewhere you can't control, then those would have to follow that convention, otherwise it won't work. – csl May 19 '11 at 20:47
0

What you want is called a closure, and C does not have explicit support for closures. You can achieve the same thing by modifying your API to carry around a function pointer and argument pointer instead of just a function pointer. Then you just need to versions of the function: one that uses the explicit caller-provided argument, and another that uses a value from the carried argument pointer.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711