В C может ли функция возвращать указатель на себя? - PullRequest
3 голосов
/ 01 февраля 2020

Фон

Так вот, что происходит, когда вы тратите несколько лет на написание Haskell, а затем go обратно на голый металл C код:

Вопрос

Возможно ли, чтобы функция имела в качестве возвращаемого типа указатель того же типа, что и сама функция? Так, каков синтаксис?

Находится ли имя функции в области видимости внутри тела функции? или я могу получить адрес функции, которая в данный момент выполняется?

Например

void foo() {
  callmeback(&foo); // is this legal
}

Зачем вам это нужно?

У меня есть конечный автомат, который обрабатывает пользовательский ввод для некоторых очень ограниченных элементов управления, что означает, что две операции ввода должны обслуживать несколько различных режимов. Я реорганизую свой спагетти-код, полный операторов switch и глобальных переменных, во что-то более легкое в обслуживании. Если бы я работал в Haskell, я бы вызвал функцию текущего режима с пользовательским вводом и заставил бы ее вернуть функцию для вызова с последующим вводом - либо сам, либо обработчик для нового режима. Я начал делать это в C и понял, что понятия не имею, как написать тип функции-обработчика. Если это не сработает, я просто установлю глобальную переменную с помощью следующего обработчика и продолжу жизнь, но мне просто нужно было спросить, можно ли это сделать так же, как на функциональном языке.

Для любопытных, все это работает на ESP32, более мощном процессоре, но похожем на то, что идет с Arduino.

Ответы [ 3 ]

3 голосов
/ 01 февраля 2020

Да , можно вернуть указатель функции на себя в C.

Тип возвращаемого вами значения - указатель void void*

И да, имя функции также отображается внутри ее тела в C. Такие вещи, как рекурсия, были бы невозможны, если бы это было не так.

Вот некоторый код для иллюстрации:

#include <stdio.h>

void* demo() // See the usage of void pointer
{
    printf("This function returns a pointer to itself");
    return &demo;
    // return demo is also fine
    // don't return demo(), that would be recursion!
}

int main()
{
    // Syntax
    void (*demoPtr)() = demo();

    // Test if it worked
    demoPtr(); // There's no problem in ignoring the return value

    return 0;
}

Вывод:

Эта функция возвращает указатель на себя

Эта функция возвращает указатель на себя

Редактировать:

После читая вторую часть вашего вопроса, в которой упоминается ваша потребность в этом, я думаю, вы, возможно, ищете рекурсию или обратный вызов . Если это так, то вы можете уточнить это в комментариях, и я соответствующим образом отредактирую свой ответ.

1 голос
/ 01 февраля 2020

Возможно ли для функции иметь в качестве возвращаемого типа указатель того же типа, что и сама функция? Так, каков синтаксис?

Это требование для рекурсивного определения типа, и это невозможно, по крайней мере, в C. Возвращение указателя на саму функцию обсуждается в этом вопросе .

Как и в других случаях, для его компиляции необходимы некоторые приемы (void* или struct s). Соответствие стандарту там не проверяется.

Находится ли имя функции в области видимости внутри тела функции?

Да, конечно. Рекурсия в порядке в C.

[…] можно ли получить адрес функции, которая в данный момент выполняется?

Просто по названию функции. Это пример вашего сценария:

#include <stdio.h>

static void caller(void (*callee)(int)) {
  printf("Begin of %s(...)\n", __func__);
  callee(23);
  printf("End of %s(...)\n", __func__);
}

static void to_be_called(int param) {
  printf("Begin of %s(%d)\n", __func__, param);
  if (param == 0) {
    caller(&to_be_called);
  }
  printf("End of %s(%d)\n", __func__, param);
}

int main(void) {
  to_be_called(0);
  return 0;
}

То, что вы планируете, не является новым во встроенном C: реализовать конечный автомат, установив указатели на функцию текущего состояния. Но вы установите следующий указатель не возвращая его , а вызвав функцию setter . Некоторые разработчики даже используют глобальную переменную для этого, brr .

0 голосов
/ 01 февраля 2020

Функции могут использовать ссылку на себя. Это на 100% нормально.

#include <stdlib.h>
#include <stdio.h>

volatile int x;

void foo(void (*fptr)())
{
    printf("Iteration: %d Function:%s\n", x++, __FUNCTION__);
    if(x < 10) fptr(foo);
}

void bar(void (*fptr)())
{
    printf("Iteration: %d Function:%s\n", x++, __FUNCTION__);
    if(x < 10) fptr(bar);
}


int main()
{
    bar(foo);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...