Сводный список записей блога

--->>>> Сводный список записей блога <<<<---

14 сентября 2021

Косвенное обращение к функции в языке Си

Мини-памятка для начинающих С-водов.

Переменная-указатель на функцию. Как сделать и как пользоваться.

При помощи указателя можно получить доступ к содержимому переменной. Это просто.
Аналогичный способ существует и для обращения к функции. И он тоже не сложный.

Очевидно, что реализация этого способа требует определения указателя на функцию. 

Делается это достаточно просто, путем объявления переменной соответствующего типа:

int (*funcptr)(int, int);

Этот пример объявляет переменную funcptr типа указатель на функцию, возвращающую результат типа int и имеющую 2 параметра типа int. Запись выглядит слегка шиворот-навыворот, но так уж требует Си - сначала нужно указать тип результата функции, затем обязательно в круглых скобках идентификатор функции (главное не забыть про звездочку – признак указателя), а затем, опять в круглых скобках, список типов параметров функции. Имена параметров тут не нужны и не важны.

Сделанная запись – не что иное, как объявление переменной с новым типом.
Можно определить этот тип при помощи typedef, после чего определять указатели на функции станет легче:

// тип указателя на функцию с 2 аргументами int и результатом int
typedef int (*t_func)(int, int);  
// переменная - указатель на функцию
t_func funcptr;

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

i = funcptr(3, 12);

Но следует помнить, что переменную-указатель нужно инициализировать. Иначе обращение к ней приведет к непредсказуемым последствиям.
Присвоение переменной адреса существующей функции очень простое.

Есть функция

int my_function(int x, int y){
  return x + y;
}

Её можно присвоить переменной funcptr:

funcptr = my_function;

С этого момента обращение к funcptr будет по факту обращением к my_function.

Адрес функции можно передавать как параметр какой то процедуры точно так же, как и другие переменные.

Помним, что у нас выше объявлен тип t_func.

Пусть есть две функции:

int my_sum(int x, int y){
  return x + y;
}

int my_mul(int x, int y){
  return x * y;
}

Делаем процедуру-агрегатор:

int agr_func(int x, int y, t_func fun){
  return fun(x,y);
}

Параметр fun с типом t_func (выделено желтым) - ни что иное, как обычный указатель на функцию. А вызов fun(x,y) - ни что иное, как вызов функции, адрес которой нам передан в параметре fun.

В основной программе делаем так:

i = agr_func(3, 4, my_sum);
j = agr_func(3, 4, my_mul);

в результате в i попадет сумма 3+4, а в j - произведение 3*4.

Материалы:
1. arv.radioliga.com
2. интернет


2 комментария:

======= !!! ВНИМАНИЕ !!! ======================================================================
Гугл умный и боится спама. Поэтому иногда ваши комментарии Гугл отправляет мне на премодерацию. Отправлять или нет - решаю не я, а алгоритмы Гугла. Если ваш комментарий не появился сразу, значит я получу уведомление и опубликую ваш комментарий через некоторое время. Я стараюсь это делать достаточно оперативно.