Общий указатель на функцию и конечные автоматы - PullRequest
3 голосов
/ 21 мая 2019

Я не могу найти в стандарте что-либо, связанное с указателями обобщенных функций, в C FAQ ( Вопрос 1.22 ), которое они используют:

typedef int (*funcptr)();         /* generic function pointer */
typedef funcptr (*ptrfuncptr)();  /* ptr to fcn returning g.f.p. */

Немного поиграю с конечными автоматами, это мой подход:

#include <stdio.h>

#define STM(x) (stm)x

typedef void (*stm)(void);
typedef stm (*pstm)(void *);

stm start(void *),
    state1(void *),
    state2(void *),
    state3(void *),
    stop(void *);

static int exit_state(int state)
{
    char str[2];
    int c;

    printf("Exit state %d? ", state);
    if (fgets(str, sizeof str, stdin)) {
        while (((c = fgetc(stdin)) != '\n') && (c != EOF));
        return (str[0] == 'y') || (str[0] == 'Y');
    }
    return 0;
}

static void state_machine(pstm pstart, void *data)
{
    pstm state = pstart;

    while (state != NULL) {
        state = (pstm)(*state)(data);
    }
}

stm start(void *data)
{
    puts("Starting state machine");
    *(char **)data = "Comes from start";
    return STM(state1);
}

stm state1(void *data)
{
    puts(*(char **)data);
    puts("State 1");
    if (!exit_state(1)) {
        return STM(state1);
    }
    *(char **)data = "Comes from state 1";
    return STM(state2);
}

stm state2(void *data)
{
    puts(*(char **)data);
    puts("State 2");
    if (!exit_state(2)) {
        return STM(state2);
    }
    *(char **)data = "Comes from state 2";
    return STM(state3);
}

stm state3(void *data)
{
    puts(*(char **)data);
    puts("State 3");
    if (!exit_state(3)) {
        return STM(state1);
    }
    return STM(stop);
}

stm stop(void *data)
{
    (void)data;
    puts("Stopping state machine");
    return NULL;
}

int main(void)
{
    char *data;

    state_machine(start, &data);
    return 0;
}

Мой вопрос: это действительно для использования

typedef void (*stm)(void);

как общий указатель на функцию?

Из того, что я вижу, видно, что мы можем использовать любой тип прототипа перед выполнением приведения, то есть

typedef long double (*stm)(unsigned long long);

также действителен

мои предположения верны?

1 Ответ

4 голосов
/ 21 мая 2019

Цитирование из: http://c -faq.com / ptrs / generic.html

гарантировано , однако, все указатели функций могут быть взаимно преобразованные , если они преобразованы обратно в соответствующий введите перед звонком. Таким образом, вы можете выбрать любой тип функции (обычно int () () или void () (), то есть указатель на функцию неопределенные аргументы, возвращающие int или void) как универсальную функцию указатель. Когда вам нужно место для хранения указателей на объекты и функции взаимозаменяемо, портативное решение состоит в том, чтобы использовать объединение пустоты * и указатель универсальной функции (любого типа, который вы выберете).

Итак, да. Это действительно для использования typedef void (*stm)(void);

ИЛИ typedef long double (*stm)(unsigned long long); как общий указатель на функцию.

Ссылки на выделенный текст по ссылке:

ISO Sec. 6.1.2.5, гл. 6.2.2.3, гл. 6.3.4 Обоснование с. 3.2.2.3 H & S Sec. 5.3.3 с. 12

РЕДАКТИРОВАТЬ: (Добавление подробностей из другого ответа)

Ссылка в черновике n1570 для C11 - 6.3 Преобразования / 6.3.2.3. Указатели § 8:

Указатель на функцию одного типа может быть преобразован в указатель на функция другого типа и обратно; результат должен сравниться равно оригинальному указателю. Если для вызова используется преобразованный указатель функция, тип которой не совместим с указанным типом, поведение не определено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...