參考:《Advanced Fortran 90: Callbacks with the Transfer Function》 Author:Drew McCormack
http://www.macresearch.org/advanced_fortran_90_callbacks_with_the_transfer_function
回調函數:
C語言中的回調函數用起來很簡單,隻要定義一個與要調用的函數具有相同參數和傳回參數的函數指針就可以使用了,例如:
#include <stdio.h>
void Woof()
{
printf("Woof\n");
}
void Meouw()
{
printf("Meouw\n");
}
typedef void (*SoundFunction)();
void MakeSoundTenTimes(SoundFunction soundFunc)
{
int i;
for ( i = 0; i < 10; ++i ) soundFunc();
}
int main()
{
MakeSoundTenTimes(Woof);
MakeSoundTenTimes(Meouw);
}
在主程式中通過把Woof和Meouw傳給
MakeSoundTenTimes
,在
MakeSoundTenTimes
裡就會分别調用Woof和Meouw函數來執行。
在Fortran90中要實作上面類似的功能要怎麼做呢? 舉例如下:
module Sounds
contains
subroutine Woof()
print *,'Woof'
end subroutine
subroutine Meouw()
print *,'Meouw'
end subroutine
subroutine MakeSoundTenTimes(soundFunc)
integer :: i
interface
subroutine soundFunc()
end subroutine
end interface
do i = 1, 10
call soundFunc()
enddo
end subroutine
end module
program main
use Sounds
call MakeSoundTenTimes(Woof)
call MakeSoundTenTimes(Meouw)
end program
看起來也很簡單!
上面的回調函數都沒有傳遞參數,如果回調函數需要傳遞參數,而且被調用函數的參數不一樣,那又該怎麼辦?
其實在C語言中很簡單,隻要在将被調用的函數的參數的類型設為void*,舉例如下:
#include <stdio.h>
void IncrementAndPrintFloat(void *data)
{
double *d = data;
(*d)++;
printf("%f\n", *d);
}
void IncrementAndPrintInteger(void *data)
{
int *i = data;
(*i)++;
printf("%d\n", *i);
}
typedef void (*IncrementFunction)(void*);
void IncrementTenTimes(IncrementFunction incrFunc, void *data)
{
int i;
for ( i = 0; i < 10; ++i ) incrFunc(data);
}
int main()
{
double f = 5.0;
int i = 10;
IncrementTenTimes(IncrementAndPrintFloat, &f);
IncrementTenTimes(IncrementAndPrintInteger, &i);
}
但是在Fortran90中并沒有類似的Void*的功能,那該怎麼辦呢? 不急,雖然Fortran90中沒有Void*但是有transfer函數啊!
下面是采用transfer函數來實作類似以上功能的例程:
module Increments
contains
subroutine IncrementAndPrintReal(data)
character(len=1) :: data(:)
real :: r
r = transfer(data, r)
r = r + 1.0
print *,r
data = transfer(r, data)
end subroutine
subroutine IncrementAndPrintInteger(data)
character(len=1) :: data(:)
integer :: i
i = transfer(data, i)
i = i + 1
print *,i
data = transfer(i, data)
end subroutine
subroutine IncrementTenTimes(incrFunc, data)
character(len=1) :: data(:)
integer :: i
interface
subroutine incrFunc(data)
character(len=1) :: data(:)
end subroutine
end interface
do i = 1, 10
call incrFunc(data)
enddo
end subroutine
end module
program main
use Increments
character(len=1), allocatable :: data(:)
integer :: lengthData
real :: r = 5.0
integer :: i = 10
lengthData = size(transfer(r, data))
allocate(data(lengthData))
data = transfer(r, data)
call IncrementTenTimes(IncrementAndPrintReal, data)
deallocate(data)
lengthData = size(transfer(i, data))
allocate(data(lengthData))
data = transfer(i, data)
call IncrementTenTimes(IncrementAndPrintInteger, data)
end program
實作起來也不太複雜。
transfer在資料類型的轉換中是非常有用的,如果想了解更詳細的内容請參考文章開頭介紹的文章。