Вызвать функцию с помощью указателя и передать его в параметрах

Скажем, у меня есть указатель на функцию theFunc. theFunc берет с собой указатель, указывающий на адрес, где хранится theFunc. Это возможно?

Использование будет выглядеть так:

funcPtr(funcPtr);

Это вызывает функцию, на которую указывает funcPtr, а затем передает адрес указателя. Я не хочу использовать пустые указатели, потому что хочу изменить функцию, на которую указывает funcPtr.

Почему использование указателя void может быть проблемой?

GalaxyShard 15.05.2022 05:55

Компилятору C/C++ нужно знать его размер, чтобы он мог генерировать правильные смещения.

ADBeveridge 15.05.2022 20:48

@ADBeveridge, ваше последнее редактирование фактически изменило вопрос. В Stackoverflow вы не должны менять вопрос после того, как есть несколько действительных ответов. Пожалуйста, вернитесь к исходному вопросу и опубликуйте новый. См. здесь: meta.stackoverflow.com/questions/290297/….

wohlstad 16.05.2022 05:26

@ADBeveridge Все указатели функций имеют одинаковый размер. Указатель функции void (как в 'void(*)(void)') не должен быть проблемой.

GalaxyShard 16.05.2022 05:47

@wohlstad, мой новый вопрос опубликован здесь

ADBeveridge 16.05.2022 22:30

@ADBeveridge спасибо. Я видел, что у тебя тоже есть ответы. Надеюсь, они помогут.

wohlstad 17.05.2022 14:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
98
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

/* Will cause a compilation error, MyFuncType used a parameter is not yet defined: */
typedef void(*MyFuncType)(MyFuncType);  

Однако вы все равно можете использовать void* для достижения желаемого. В typedef используется void*, но внутри функции вы можете привести его к типу указателя на функцию, изменить его и вызвать.

Глянь сюда:

typedef void(*MyFuncType)(void*);

void f(void* pF)
{
    if (pF)
    {
        MyFuncType ff = (MyFuncType)pF;
        /* Change ff here if you need. */
        /* Call it: */
        ff(0);
    }
}

int main()
{
    f(f);
    return 0;
}

Обновлять:
Следуя комментарию @JosephSible-ReinstateMonica ниже, я добавил решение 2-й. Он не включает приведение между указателями данных и функций, но требует еще одного typedef и приведения при вызове f с самим собой:

typedef void(*FuncType1)(void);
typedef void(*MyFuncType)(FuncType1);

void f(MyFuncType pF)
{
    if (pF)
    {
        /* Change pF here if you need. */
        /* Call it: */
        pF(0);
    }
}

int main()
{
    f((MyFuncType)f);
    return 0;
}

Нет никакой гарантии, что вы сможете безопасно преобразовать указатель на функцию в указатель на данные. Вероятно, вы хотели написать что-то вроде typedef void(*MyFuncType)(void(*)(void));, а затем аналогичным образом настроить f.

Joseph Sible-Reinstate Monica 15.05.2022 05:28

@JosephSible-ReinstateMonica, но если я изменю MyFuncType, как вы предложили, и изменю f так: void f(void(*pF)(void)) я больше не смогу использовать f(f), чтобы вызывать его сам по себе. Я понимаю, что преобразование указателя данных в указатель на функцию может вызвать проблемы, но это единственный способ заставить его работать (пока я передаю действительную функцию в качестве аргумента). Пожалуйста, покажите, как это можно сделать, если я вас неправильно понял.

wohlstad 15.05.2022 05:49

Разве вы не можете просто добавить дополнительный актерский состав, чтобы заставить его работать?

Joseph Sible-Reinstate Monica 15.05.2022 05:51

@JosephSible-ReinstateMonica Я обновил свой ответ вторым решением после ваших комментариев.

wohlstad 15.05.2022 06:09

Да. Это возможно. C поддерживает неполные типы функций в виде функций, объявленных без прототипов. Например:

int fun();

Объявляет функцию, которая принимает неопределенное количество аргументов и возвращает int. Это позволяет определить каскад типов функций, приближающихся к желаемому типу функции, который принимает указатель на себя в качестве первого аргумента. Желаемый тип достигается на бесконечности, но для практической безопасности типов достаточно 2-3 уровней.

Например, приведенный ниже код компилируется без предупреждения даже в педантичном режиме.

int foo(int(int()));

int main(void) {
  int (*fptr)(int(int())) = foo;
  return fptr(fptr);
}

См. https://godbolt.org/z/1s1bGMd9P

theFunc takes along a pointer that points to the address where theFunc is stored . Is this possible?

Да, это возможно, но это также 100% бессмысленно. Это похоже на то, как адресовать письмо самому себе, записывая в письме свой почтовый адрес. Вы идете, чтобы поместить это письмо в свой почтовый ящик, в то время как вы уже находитесь по этому физическому адресу, указанному в письме. Это не имеет никакого смысла — вы уже знаете адрес, поскольку вы уже там, так зачем вообще писать письмо? Правило № 1 в разработке программы: не делайте действительно странных вещей только потому, что можете.

Любое имя функции в C может превратиться в указатель на функцию при использовании в выражении. Таким образом:

void theFunc (void)
{
  uintptr_t address = (uintptr_t)theFunc;
}

Нет необходимости в каких-либо параметрах.

Другие вопросы по теме