Возврат указателя на функцию из функции и вызов ее с помощью указателя. Как именно это работает?

#c #function #function-pointers #function-call

#c #функция #указатели на функции #функция-вызов #функции-указатели #вызов функции

Вопрос:

Итак, возьмите следующий код, я читал несколько конспектов лекций по указателям на функции, и я наткнулся на это:

 int (*Convert(const char code))(int, int) {
    if (code == ‘ ’) return amp;Sum; // Takes two ints, and adds
    if (code == ‘-’) return amp;Difference; // Takes two ints, and subtracts
} 

int main () {
    int (*ptr)(int,int);
    ptr = Convert(‘ ’);
    printf( “%dn”, ptr(2,4));
} 
  

Обычно я привык видеть что-то подобное при вызове функции, которая возвращает указатель на функцию, и для меня это имеет смысл, поскольку у меня есть все параметры, изложенные здесь char , и два int :

 Convert('-')(5, 6);
  

Но из-за того, как это было написано в заметках, я не могу по-настоящему понять, что именно здесь происходит. Может кто-нибудь рассказать, как именно это работает? Связано ли это с присвоением (*ptr)(int, int) адреса функции или что-то в этом роде?

Комментарии:

1. Это должно было вызвать у вас головную боль. Ничего, что нельзя было бы исправить с помощью typedef , всегда что-то, что вы хотите сделать с типами указателей на функции. Используйте typedef int (*converter)(int left, int right); . Теперь он становится читаемым вместо lisp: конвертер Convert(const char code) {…}

Ответ №1:

Может кто-нибудь рассказать, как именно это работает? Связано ли это с присвоением (* ptr)(int, int) адреса функции или что-то в этом роде?

Функция Convert() возвращает указатель на функцию — либо указатель на Sum() , либо указатель на Difference() , в зависимости от ее аргумента (или она завершается без указания возвращаемого значения, что является плохой новостью для вас, если вы вообще что-либо делаете с возвращаемым значением). Этот указатель на функцию хранится в переменной ptr , которая объявлена как имеющая тот же тип, Convert() что и returns . Затем указанная функция может быть вызвана с помощью оператора вызова функции, () .

Возможно, это было бы немного понятнее, если бы было переписано таким эквивалентным образом с использованием typedef :

 typedef int (*op_function)(int, int);

op_function Convert(const char code) {
    if (code == ‘ ’) return amp;Sum; // Takes two ints, and adds
    if (code == ‘-’) return amp;Difference; // Takes two ints, and subtracts
} 

int main () {
    op_function ptr;
    ptr = Convert(‘ ’);
    printf( “%dn”, ptr(2,4));
}
  

Ответ №2:

Либо есть опечатка, либо вы имеете в виду имя функции AddSub вместо Convert .

Например

 int (*AddSub(const char code))(int, int) {
    if (code == ‘ ’) return amp;Sum; // Takes two ints, and adds
    if (code == ‘-’) return amp;Difference; // Takes two ints, and subtracts
}
  

[Примечание: обратите внимание на то, что использование оператора amp; является избыточным из-за неявного преобразования обозначения функции в указатель на функцию, например

 int (*AddSub(const char code))(int, int) {
    if (code == ‘ ’) return Sum; // Takes two ints, and adds
    if (code == ‘-’) return Difference; // Takes two ints, and subtracts
}
  

-конечная заметка.]

Итак, вызывая функцию, как

 AddSub('-');
  

вы получите выражение типа указатель на функцию типа int( int, int ). , и вы снова можете предоставить аргументы возвращаемому указателю, чтобы вызвать указанную функцию, например

 AddSub('-')(5, 6);
  

Чтобы сделать его более понятным, вы можете переписать приведенное выше выражение следующим образом

 ( AddSub('-') )(5, 6);
  

Это то же самое, что и этот фрагмент кода

 int ( *ptr )( int, int ) = AddSub(‘ ’);
printf( “%dn”, ptr(2,4));
  

но без промежуточной переменной ptr .

 printf( “%dn”, AddSub( ' ' )(2,4) );
  

Ответ №3:

Указатели на функции сохраняют ссылку на функцию и могут быть вызваны, но они ведут себя точно так же, как и другие указатели. Синтаксис многих людей сбивает с толку, и это одно из мест, где скрытие указателей за typedefs имеет смысл, но в этом нет необходимости

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

typedef int func(int, int);

int Difference(int a, int b){
    return a - b;
}

int Sum(int a, int b){
    return a   b;
}

func *Convert(const char code) {
    if (code == ' ') return Sum; // Takes two ints, and adds
    if (code == '-') return Difference; // Takes two ints, and subtracts
} 

int main () {
    func *ptr;
    ptr = Convert(' ');
    printf( "%dn", ptr(2,4));
}