Rapid-Q Documentation by William Yu (c)1999 Глава 11


11. Использование указателей (адресов) на функции.
(
Using Function Pointers)

Не знаю, видели ли вы указатели на функции в языке Basic? В Rapid-Q указатели на функции несколько отличаются от того, чем люди обычно пользуются. Они несколько необычны, как я предполагаю, но большинство важных особенностей здесь изложено, таких как переопределение указателей на функции и динамические указатели. К сожалению (as of this writing) вы не можете передавать указатели на функцию, как аргументы.
 
Didn't think you'd see function pointers in a BASIC programming language did you? Well, in Rapid-Q function pointers are a bit different from what most people are used to. There are a few oddities I guess, but most of the important features are there, like redefining function pointers, and dynamic function pointers. Unfortunately (as of this writing), you can't pass function pointers as arguments.

 
11.1    Основные понятия  (Introduction to the concept)
Отлично, что же такое указатели на функцию?
Функция (SUB or FUNCTION) занимает  какое-то место в памяти. Указатель на эту функцию -  это просто ее адрес. Так, если я знаю адрес функции, то я могу перейти  на него и выполнить содержащийся там код. На низком уровне кода - сохраните параметры в стеке и перейдите (т.е. вызовите -Call ) функцию. Но если указатель - это просто число, как мы найдем адрес функции? Этот вопрос мы рассмотрим следующим..
 
Great, so what are function pointers? I know a lot people are tired of terminology, only because the definition is probably a lot easier to understand/grasp. It helps to understand how things are stored in memory and addressed. For example, a function (ie. SUB or FUNCTION) occupies space in some address space somewhere. A pointer to that function is just the address of it. So if I know the address of the function, I can jump into that "process space" and execute the code within. This is the low level way of thinking, first push the parameters, and then jump to (ie. CALL) the function. So if pointers are only numbers, how do we find the address of the function? This is the question that will be considered next.

11.2    Определение указателя на функцию ( Defining function pointers )
Если у вас  уже есть опыт работы с указателями на функцию (например в С), вы должны обратить внимание на некоторые отличия.
В Rapid-Q, поскольку указатели - это просто числа,  вы можете использовать любые числовые типы для определения указателей на функцию.
Кажется странным, да, но указатели - это просто числа. Избегайте использовать тип
BYTE , так как адрес функции может быть гораздо больше, чем 255. Используйте INTEGER/LONG
 
    DECLARE SUB Test (I AS INTEGER)

    DIM FPtr AS INTEGER

    BIND FPtr TO Test
Вот так, мы используем BIND , чтобы связать нашу переменную FPtr с адресом функции. Это сделает две вещи - очевидно FPtr  укажет на адресное пространство функции Test, но также свяжет число параметров с указателем FPtr, это необходимо, чтобы компилятор знал, сколько параметров надо передавать/принимать. Для вызова нашей функции мы должны использовать резервированное слово CALLFUNC.
    CALLFUNC(FPtr, 120)
Это вызовет подпрограмму TEST с одним параметром. Очевидно, это не очень полезный пример, рассмотрим, где это может быть полезным.
    DECLARE SUB Test1 (I AS INTEGER)
    DECLARE SUB Test2 (I AS INTEGER)

    DIM FPtr(1 TO 2) AS INTEGER

    BIND FPtr(1) TO Test1
    BIND FPtr(2) TO Test2

Когда вы связываете массивы, отметьте, что первая функция котрая связана будет являться шаблоном для всех
последующих элементов. Например, имеем массив FPtr, и через Bind привязываем FPtr(1)к SUB Test1. FPtr теперь привязан.
Это значит, что если вы привязываете любой другой FPtr(i), функция должна иметь соответствующее число параметров.
Может быть пример поможет лучше понять это.

    DECLARE SUB Test1 (I AS INTEGER)
    DECLARE SUB Test2 (I AS INTEGER, J AS STRING)

    DIM FPtr(1 TO 2) AS INTEGER

    BIND FPtr(1) TO Test1
    BIND FPtr(2) TO Test2
Второй BIND  неверен, так как число параметров Test2 не соответствует с Test1. Вы получите сообщение об ошибке, когда попытаетесь так сделать. Отметьте, что речь идет о несоответствии числа параметров, а не типа параметров. Соответствие типов необязательно, но результат может быть неопределенный.


11.3 Правильное использование  указателей на функции (Using function pointers properly )

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


     SELECT CASE I
       CASE 1
         Process1("1", 44)
       CASE 2
         Process2("2", 55)
       CASE 3
         Process3("3", 66)
       CASE 4
         :
         :
      etc...


Это  может быть  например, меню с несколькими опциями, или возможно синтаксический анализатор (да Rapid-Q использует указатели функции, чтобы анализировать ваш код). Как Вы можете видеть, имеется здесь требуется  произвести много операций сравнения, особенно, если вы пишете синтаксический анализатор, где имеются  много ключевых слов (более  50). Эти операции мы можем легко выполнить, используя указатели на  функции,  что ускорит нашу программу.

(См. FUNCPTR.BAS с  примером.)

     BIND FPtr(1) AS Process1
     BIND FPtr(2) AS Process2
     BIND FPtr(3) AS Process3
     BIND FPtr(4) AS Process4
     BIND FPtr(5) AS Process5
     BIND FPtr(6) AS Process6
     BIND FPtr(7) AS Process7

     x = VAL(INPUT$(1))
     CALLFUNC(FPtr(x), 33)

Я думаю  можно понять общую идею.

None of the code you see above is executable as is, but I think you get the general idea. We don't need any case statements as you can see (this is assuming you've partitioned your function pointers properly).

11.4 Что не поддерживается в Rapid-Q . (What is not supported in Rapid-Q )


Указатели на функции в качестве аргументов не поддерживаются, хотя это может быть очень полезно.
Вы можете передать величину указателя на функцию, как аргумент, но вы нетможете при этом вызывать функцию.
Единственный способ  состоит  в том, чтобы определить глобальный указатель функции как ваш шаблон, и затем назначать его к вашему параметру.
Например
:
     DECLARE FUNCTION MyFuncTemp (X AS LONG) AS LONG
     DECLARE FUNCTION Func1 (X AS LONG) AS LONG
     DECLARE FUNCTION Func2 (X AS LONG) AS LONG

     DIM Template AS INTEGER
     DIM I(100) AS INTEGER

     BIND Template TO MyFuncTemp
     BIND I(1) TO Func1
     BIND I(2) TO Func2

     SUB Test (FPtr AS INTEGER)
        Template = FPtr
        PRINT CALLFUNC(Template, 10)
     END SUB

     Test I(1)
Это пожалуй единственный спрособпреодолеть это ограничение.


Prev Глава Up Содержание Next Глава
ODY>