Fortran与C语言,回调函数的使用比较

参考:《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在数据类型的转换中是非常有用的,如果想了解更详细的内容请参考文章开头介绍的文章。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值