How to raise a function to take an extra parameter in C?

(I understand that C is not intended to be used in a functional way. However, having studied functional programming, I have problems with thinking differently.)

Given these limitations:

  • There are no nested functions because clang forbids this (so there are no lamda expressions)
  • no global variables

Is it possible to come up with a way to raise the function f to take an additional parameter to match the prototype, for example, this new parameter will be ignored when f is executed?

Here is what I want to do in detail:

I want to install a function f whose type is:

f :: void f(char *s) 

in the function g, which takes a function as an argument (let's call it arg), whose type is:

 arg :: void f(unsigned int i, char *s) 

So type g:

 g :: void g(void (*f) (unsigned int, char)) 

The solution in haskell will be as follows:

 g (const f) 

Is this possible, perhaps with some kind of macro magic?

EDIT. To provide a better understanding, here is the actual code. The ft_striter body must be completed. Purpose: apply the function f to each character of the string, using or not using its index i.

 void ft_striter(char *s, void (*f) (char *s)) { ft_striteri(?); } static void ft_striteri_helper(char *s, unsigned int i, void (*f)(unsigned int, char*)) { if (*s) { f(i, s); ft_striteri_helper(s + 1, i + 1, f); } } void ft_striteri(char *s, void (*f)(unsigned int, char*)) { ft_striteri_helper(s, 0, f); } 
+6
source share
3 answers

You cannot implement this in the standard portable C. The problem is that the function g . wrong. It must be of type

 void g(void (*f) (void *, unsigned int, char), void *ctxt) 

and he should pass his ctxt argument as the first argument to any f calls he makes.

Now you can implement what you want with code like

 struct const_ctxt { void (*fun)(char *); } void const(void *ctxt, unsigned int i, char *s) { ((struct const_ctxt *)ctxt)->fun(s); } void call_g_using_const_f(void (*f)(char *)) { struct const_ctxt *ctxt = malloc(sizeof (struct const_ctxt)); ctxt->fun = f; g(const, (void *)ctxt); free(ctxt); } 

A warning. If the arguments g can go out of the dynamic region g , you will need to find another strategy for controlling the distribution of ctxt s.

Sample g , containing a pair of code pointer and context / data pointer, is how higher-level languages ​​typically implement closures.

+4
source

Since you only want to accept and ignore the optional parameter, you can accomplish this by creating a wrapper function with the necessary signature that simply delegates the original function:

 void f2(unsigned int i, char *s) { f(s); } 

With the correct declaration of this function in scope, you can simply call

 g(f2); 

The f2() function can be declared static if you want it not to be visible to code outside the file in which it is defined. It does not need to be inserted.

+2
source

Well consider a few options.

First, C has no lambda expressions, although the latest C ++ is standard. It might be worth considering C ++ instead of C if this is a serious problem for you.

C can define and pass function pointers . Therefore, it is completely legal to pass a function as a parameter to another function.

You can also define functions for accepting a variable number of arguments , which may also be useful to you.

C macros can also be useful. You can, for example, do this:

 #define f1( x ) g( (x), 1 ) #define f2( x ) g( (x), 2 ) int g( int x, int y ) { return ( x + y ) ; } 

You can even do smart things with macros to allow macro overloading. This is not entirely ideal in terms of coding style, but it is possible.

Thus, there may be some tools to get what you want.

Update

The OP added an update to his post while I was about to, so if I understand that his goal is here, this is a rude suggestion.

It seems that the OP wants the selected function to have access to the index variable, which can be set in another place where it could try to use struct for parameters. Perhaps something like:

 typedef struct mystring_s { char *s ; int i ; } mystring_t ; void f1( mystring_t *strp ) { /* can access strp->s and strp->i */ } /* and similar for other functions f2, f2, etc. */ /* And to use this you can call any function using */ void g( void (*fn)( mystring_t * ), mystring_t *strp ) { (*fn)( strp ) ; } void set_i( mystring_t *strp, int v ) { strp->i = v ; } /* for example */ mystring_t s ; /* set up s */ set_i( &s, 11 ) ; g( &f1, &s ) ; set_i( &s, 31 ) ; g( &f2, &s ) ; 

Of course, he could also try to use a global value (which he apparently doesn't want or doesn't think is impossible), and he could even store a function pointer with data.

It's hard to know for sure if this is a workable idea for the OP, as it is really trying to do what C is not intended for. I think the problem is that he has a design idea in his head, and this is a bad choice for C. Perhaps it would be better to see how these requirements arose and change this overall design to something more C friendly than trying and make C to replace the capabilities of Haskell.

-1
source

All Articles