Как выполнить общий код до и после другой функции в c? - PullRequest
0 голосов
/ 26 сентября 2018

Здесь я объясняю проблему.Предположим, у меня есть структура A, загруженная в общую память.Структура A может выглядеть примерно так:

typedef enum{
    GPIO_1,
    GPIO_2,
    GPIO_3,
    GPIO_4,
    GPIO_5,
    N_GPIO
} gpio;

struct B {
    bool active;
    bool status;
    bool direction;
    int timestamp;
    int t1;
    int t2;
};

struct A {
    struct B gpio[N_GPIO];
};

Также предположим, что у меня есть две функции, которые будут работать с одной из структур B в A:

bool set_status(gpio g, bool status, int t1, int t2);
bool activate(gpio g, bool active);

Поскольку A загружается вразделяемой памяти, мне нужно вызвать shmget и shmdt в рамках двух функций выше;псевдокод для первой функции должен выглядеть примерно так:

bool set_status(gpio g, bool status, int t1, int t2) {
    struct A shm = shmget();
    struct B target = shm.gpio[g];
    if(target.active) {
        bool res = foo1(target, status, t1, t2); //do something on struct B indexed by g
        shmdt();
        return res;
    else 
        return false;
}

псевдокод для второй функции должен выглядеть примерно так:

bool activate(gpio g, bool active) {
    struct A shm = shmget();
    struct B target = shm.gpio[g];
    if(target.active) {
        bool res = foo2(target, active); //do something on struct B indexed by g
        shmdt();
        return res;
    else
        return false;
}

Теперь есть способ, которым я могупомешать иметь тот общий код, который управляет shm и проверяет, установлен ли B.active?Для меня это выглядит как декораторы, то есть иметь функцию, которая управляет shm, проверяет B.active и вызывает в ней вторую функцию, но проблема в том, что вторая функция может иметь не уникальную подпись (может иметь другое числопараметров).

Я хотел бы иметь что-то вроде этого:

bool set_status(gpio g, bool status, int t1, int t2) {
    return decorator(foo1, g, status, t1, t2); //do something on struct B indexed by g
}

bool activate(gpio g, bool active) {
    return decorator(foo2, g, active); //do something on struct B indexed by g
}

таким образом, чтобы декоратор управлял shm и проверял на целевой B.active.

Спасибо!

РЕДАКТИРОВАТЬ: вот минимальный рабочий пример, который вы можете реорганизовать https://github.com/oliviera9/c_decorator

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Вы можете создать макрос с переменным значением:

#define DECORATOR(fn, g, ...) \
    struct A shm = shmget(); \
    struct B target = shm.gpio[(g)]; \
    if(target.active) { \
        bool res = (fn)(__VA_ARGS__)\
        shmdt(); \
        return res; \
    } else {\
        return false; \
    }

И использовать его вот так

bool set_status(gpio g, bool status, int t1, int t2) {
    DECORATOR(foo1, g, status, t1, t2)
}

bool activate(gpio g, bool active) {
    DECORATOR(foo2, g, active)
}
0 голосов
/ 26 сентября 2018

Сколько взлома тебе разрешено делать?Вам разрешено менять foo1 и foo2?Поскольку вы могли бы что-то сделать с указателями на функции и приведением указателей:

Во-первых, ваша decorator -функция будет принимать указатель на функцию, поэтому foo1 и foo2 требуют одинаковую сигнатуру функции:

bool foo1(struct B t, void* args);
bool foo2(struct B t, void* args);

Чтобы передать аргументы этим двум функциям, я бы предложил несколько структур:

typedef struct {
  bool status;
  int t1;
  int t2;
} foo1_args;

typedef struct {
  bool active;
} foo2_args;

И затем приведу эти аргументы внутри foo1 и foo2:

bool foo1(struct B t, void* args) {
  foo1_args* my_args = (foo1_args*)args;
  bool status = my_args->status;
  // ...
}

bool foo2(struct B t, void* args) {
  foo2_args* my_args = (foo2_args*)args;
  bool active = my_args->active;
  // ...
}

Далее следует функция декоратора, которая выполняет общие функции и вызывает указатель функции с указанными аргументами:

bool decorator(gpio g, bool (*func)(struct B, void*), void* args) {
  struct A shm = shmget();
  struct B target = shm.gpio[g];
  if (target.active) {
    bool res = func(target, args);  // do something on struct B indexed by g
    shmdt();
    return res;
  } else
    return false;
}

И, наконец, ваши activate или set_status функции:

bool set_status(gpio g, bool status, int t1, int t2) {
  foo1_args args = {status, t1, t2};
  return decorator(g, foo1, &args);
}
...