Is there a way to save a function call with parameters?

I am experimenting with memory management and trying to create something that will help with it. Right now I'm trying to think if there is a way to replicate the defer functionality from Go in C.

A quick example for those who do not know what defer is:

package main

import "fmt"

func main() {
    defer fmt.Println("1")
    defer fmt.Println("2")
    defer fmt.Println("3")
    return
}

will print

3
2
1

So, I’m thinking about some macros that will call a function with parameters on some stack and will call them when the function is called. Something like that:

int func(void)
{
    MEMSTACK_INIT;

    char * string = NULL;
    node_t * node = NULL;
    MEMSTACK_PUSH(free(string));
    MEMSTACK_PUSH(NodeFree(&node));

    <..>

    switch (something)
    {
    case ONE : RETURN ERROR_ONE;
    case TWO : RETURN ERROR_TWO;
    case THR :
        switch (something else)
        {
            <.. Many more code ..>
        }
    }        

    RETURN ERROR_GOOD;
}

Is there a way (with the exception, of course, of my own preprocessor) to store a function call with parameters somewhere? In other words, I want the previous code to be pre-processed as follows:

int func(void)
{
    <.. Some MEMSTACK initialisation stuff (if needed) ..>

    char * string = NULL;
    node_t * node = NULL;

    <..>

    switch (something)
    {
    case ONE :             
        free(string);
        NodeFree(&node);
        return ERROR_ONE;
    case TWO :             
        free(string);
        NodeFree(&node);
        return ERROR_TWO;
    case THR :
        switch (something else)
        {
            <.. Many more code ..>
        }
    }        

    free(string);
    NodeFree(&node);
    return ERROR_GOOD;
}

It would be nice if features requiring a lot of cleanup before exiting. Yes, yes, I know the trick goto cleanup.

+4
1

-, .

, return . , (, goto , ). , : , ( ) !

...

[..] defer Go C.

-, , ( ), . C , :

struct Fn {
  void * parameters; // pointer to memory where the parameters are stored
  void (*function)(void *); // pointer to function able to unpack parameters from above
  struct Fn * next; // we want a stack, so ...
};

, , . , a struct, , struct:

#define MAKE_DEFERRABLE(name, N, ...) \
  struct deferred_ ## name ## _parameters { PARAMS(N, __VA_ARGS__) }; \
  void deferred_ ## name (void * p) { \
    struct deferred_ ## name ## _parameters * parameters = p; \
    printf(" -- Calling deferred " #name "\n"); \
    (void)name(CPARAMS(N)); \
  }

N - . , , __VA_ARGS__, . , PARAMS CPARAMS. , struct. struct :

#define PARAM_0(...)
#define PARAM_1(type, ...) type p1; PARAM_0(__VA_ARGS__)
#define PARAM_2(type, ...) type p2; PARAM_1(__VA_ARGS__)
#define PARAM_3(type, ...) type p3; PARAM_2(__VA_ARGS__)
#define PARAM_4(type, ...) type p4; PARAM_3(__VA_ARGS__)
#define PARAMS(N, ...) SPLICE(PARAM_, N)(__VA_ARGS__)

#define CPARAM_0 
#define CPARAM_1 parameters->p1
#define CPARAM_2 parameters->p2, CPARAM_1
#define CPARAM_3 parameters->p3, CPARAM_2
#define CPARAM_4 parameters->p4, CPARAM_3
#define CPARAMS(N) SPLICE(CPARAM_, N)

4 , . SPLICE - :

#define SPLICE_2(l,r) l##r
#define SPLICE_1(l,r) SPLICE_2(l,r)
#define SPLICE(l,r) SPLICE_1(l,r)

- . :

struct Fn * deferred_fns = NULL;

, : () , , deferred_fns, alloca,...

... , ( ):

#define DEFER(name, N, ...) \
  do { \
    printf(" -- Deferring a call to " #name "\n"); \
    if (deferred_fns == NULL) { \
      deferred_fns = malloc(sizeof(*deferred_fns)); \
      deferred_fns->next = NULL; \
    } else { \
      struct Fn * f = malloc(sizeof(*f)); \
      f->next = deferred_fns; \
      deferred_fns = f; \
    } \
    deferred_fns->function = &(deferred_ ## name); \
    struct deferred_ ## name ##_parameters * parameters = malloc(sizeof(*parameters)); \
    SPARAMS(N,__VA_ARGS__); \
    deferred_fns->parameters = parameters; \
  } while(0)

struct Fn, ( deferred_fns) . SPARAMS struct:

#define SPARAM_0(...)
#define SPARAM_1(value, ...) parameters->p1 = (value); SPARAM_0(__VA_ARGS__)
#define SPARAM_2(value, ...) parameters->p2 = (value); SPARAM_1(__VA_ARGS__)
#define SPARAM_3(value, ...) parameters->p3 = (value); SPARAM_2(__VA_ARGS__)
#define SPARAM_4(value, ...) parameters->p4 = (value); SPARAM_3(__VA_ARGS__)
#define SPARAMS(N, ...) SPLICE(SPARAM_, N)(__VA_ARGS__)

. , . C .

, , , :

void run_deferred_fns(void) {
  while (deferred_fns != NULL) {
    deferred_fns->function(deferred_fns->parameters);
    free(deferred_fns->parameters);
    struct Fn * bye = deferred_fns;
    deferred_fns = deferred_fns->next;
    free(bye);
  }
}

:

void foo(int x) {
    printf("foo: %d\n", x);
}
void bar(void) {
    puts("bar");
}
void baz(int x, double y) {
    printf("baz: %d %f\n", x, y);
}
MAKE_DEFERRABLE(foo, 1, int);
MAKE_DEFERRABLE(bar, 0);
MAKE_DEFERRABLE(baz, 2, int, double);

int main(void) {
  DEFER(foo, 1, 42);
  DEFER(bar, 0);
  DEFER(foo, 1, 21);
  DEFER(baz, 2, 42, 3.14);
  run_deferred_fns();
  return 0;
}

, , deferred_fns run_deferred_fns. , :

#define PREPARE_DEFERRED_FNS struct Fn * deferred_fns = NULL;
#define RETURN(x) do { run_deferred_fns(deferred_fns); return (x); } while (0)

.

. " ". , . , , , , dlopen. , ABI, : avcall, libffcall.

... (()))) (() (((()

+2
source

All Articles