Нравится? Делимся информацией!

воскресенье, 16 июня 2013 г.

Немного о указателях на функцию



Решил поиграться с указателями на функцию (callback, функции обратного вызова) и массивом указателей на функцию.
Что это?

Функция располагается в памяти по определенному адресу, который можно присвоить указателю в качестве его значения. Адресом функции является ее точка входа. Именно этот адрес используется при вызове функции. Так как указатель хранит адрес функции, то она может быть вызвана с помощью этого указателя. Он позволяет также передавать ее другим функциям в качестве аргумента. В программе на С адресом функции служит ее имя без скобок и аргументов (это похоже на адрес массива, который равен имени массива без индексов).
Чтобы понять где это используется, читаем Википедию про функции обратного вызова


Небольшой ликбез.
Объявление указателя на функцию:
int (*pt2Function)(float, char, char) = NULL;                        // C
int (TMyClass::*pt2Member)(float, char, char) = NULL;                // C++
int (TMyClass::*pt2ConstMember)(float, char, char) const = NULL;     // C++


Присвоение указателю на функцию адреса функции: это просто. Просто берете имя уже объявленной и определенной функции и перед ним добавляете операцию взятия адреса &. Хотя на многих компиляторах можно ее опустить, но для написания переносимого когда использование & обязательно!!!
// C
int DoIt  (float a, char b, char c){ printf("DoIt\n");   return a+b+c; }
int DoMore(float a, char b, char c)const{ printf("DoMore\n"); return a-b+c; }

pt2Function = DoIt;      
// short form
pt2Function = &DoMore;   
// correct assignment using address operator
// C++
class TMyClass
{
public:
  
int DoIt(float a, char b, char c){ cout << "TMyClass::DoIt"<< endl; return a+b+c;};
  
int DoMore(float a, char b, char c) const
        { cout <<
"TMyClass::DoMore" << endl; return a-b+c; };

  
/* more of TMyClass */
};

pt2ConstMember = &TMyClass::DoMore;
// correct assignment using address operator
pt2Member = &TMyClass::DoIt;
// note: <pt2Member> may also legally point to &DoMore
Конец.


Идея в том, чтобы создать массив указателей на функцию. В определенном порядке инициализировать каждый элемент массива адресом определенной функции, а затем строить поведение программы, играясь индексом этого массива. Это идея - предтеча другой идеи, о которой я пока говорить не хочу...
Итак, сделаем зарядку. Обычно при зарядке ведут счет: Раз, Два, Три, Четыре, Три, Четыре, Раз, Два... Надеюсь, текст программы будет понятен.


#include <stdio.h>
/* type definition: 'pfunction' now can be used as type */
typedef void (*pFunction) (void);void one (void)
{
   printf("%
s(): ONE\n",__func__);
}


void two (void)
{
   printf("%
s(): TWO\n",__func__);
}


void three (void)
{
   printf("%
s(): THREE\n",__func__);
}


void four (void)
{
   printf("%
s(): FOUR\n",__func__);
}


int main(void) {
   printf("%s \n", __func__);
   int counter;
   /* define arrays and initialize each element to NULL */
   pFunction funcArray[8] = {NULL};

   /* assign the function's address  */
   funcArray[0] = funcArray[6] = &one; /* correct assignment using address operator */
   funcArray[1] = funcArray[7] = &two;
   funcArray[2] = funcArray[4] = &three;
   funcArray[3] = funcArray[5] = &four;
       
   /* calling a functions using an index to address the function pointers */
   for (counter = 0; counter < 8; ++counter) {
       funcArray[counter]();
   }

   return 0;
}
В программе я просто в цикле for() организую последовательный вызов callback’ов, изменяя индекс массива указателей. Однако - идея №2 - индекс может изменяться под воздействием, например, volatile переменной, которая, к примеру, меняется в прерывании, или же переменная - это значение I/O порта, настроенного на вход, и в соответствии с этим изменяется поведение основной нити программы. Но это только идея, а так как я особо не видел применение Идеи №2 на практике, то это просто идея побаловаться.
Результат работы:
main
one(): ONE
two(): TWO
three(): THREE
four(): FOUR
three(): THREE
four(): FOUR
one(): ONE

two(): TWO

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

Отправить комментарий