Обратный вызов указателя функции C как член структуры с параметром ссылки на себя


Я хочу создать структуру задачи, содержащую указатель функции на обратный вызов для выполнения указанной задачи. Задача содержит параметры, поэтому я хотел бы передать указатель "this/self" структуры на функцию исполнителя обратного вызова. Это создает циклические зависимости, и я копался в различных предварительных объявлениях и т. Д., Но, похоже, не могу понять это правильно. Я упускаю что-то, что делает это невозможным, или просто мое волшебство синтаксиса C ужасно слабое. Изменение задачи* на пустоту* похоже на читерство?

в задаче.ч:

// create a function pointer type signature for executing a task
typedef int (*executor) (task* self);

// create a task type
typedef struct {
    executor exec;  // the callback to execute the task
    ... // various data for the task
} task;

person netjiro    schedule 12.05.2015    source источник


Ответы (3)


Вперед объявите struct task, затем объявите указатель функции, используя struct task, затем объявите struct task и typedef task.

struct task;
typedef int (*executor) (struct task* self);

typedef struct task {
    executor exec;  // the callback to execute the task
    ... // various data for the task
} task;

Или, как предложил Йенс:

Сначала typedef task с предварительным объявлением struct task, затем объявите указатель функции (используя typedef task) и struct task.

typedef struct task task;
typedef int (*executor) (task* self);

struct task {
    executor exec;  // the callback to execute the task
    ... // various data for the task
};
person Werner Henze    schedule 12.05.2015
comment
Будет еще проще, если вы начнете с typedef struct task task; - person Jens Gustedt; 12.05.2015
comment
Вау, суперспасибо. Да, мой синтаксис C слаб. - person netjiro; 12.05.2015
comment
Мне нужно прочитать об идиоматическом использовании typedef struct typename {} typename и о том, что это на самом деле означает для компилятора. - person netjiro; 12.05.2015
comment
придется подождать несколько минут, прежде чем я смогу принять ответ... но спасибо! сэкономил мне много времени. - person netjiro; 12.05.2015

Вы должны добавить объявление incomplete type перед тем, как сообщить компилятору, что тип будет определен позже. Вы можете «злоупотреблять» тем фактом, что так называемые структурные теги имеют свое собственное пространство имен, отдельное от имен типов. Таким образом, имя структурного тега может совпадать с именем типа:

typedef struct task task; // typedef a struct task as "task"
typedef int (*executor) (task* self); // pointer to incomplete type

typedef struct task { // re-use struct tag name here to complete the type
    executor exec;
} task; // typedef a name for the completed type

...
task t;
person Lundin    schedule 12.05.2015

Typedef и forward сначала объявляют структуру, и она должна работать, вот так:

#include <stdio.h>

typedef struct task task;
typedef int (*executor) (task* self);

struct task {
    executor exectr;
    int a;
};

int exec(task* self) {
    return self->a;
}

int main(int, char**) {
    task a = { .exectr = exec, .a=10};
    printf("%d\n",a.exectr(&a));
    return 0;
}
person alagner    schedule 12.05.2015