【Fortran】Fortran可选参数optional和接口interface的示例程序

本文档展示了一个Fortran模块`mod_tools`,其中包含多个子程序,这些子程序使用可选参数。通过`test_optional`接口,实现了不同维度数组的实数和整数类型可选参数的处理。在`Main`程序中调用了这些子程序,演示了如何传递可选参数并检查其是否存在。此代码示例详细解释了Fortran中可选参数的使用和接口声明。

代码

module mod_tools
  implicit none

  integer,parameter :: its = 1
  integer,parameter :: ite = 4
  integer,parameter :: jts = 1
  integer,parameter :: jte = 3
  integer,parameter :: kms = 1
  integer,parameter :: kme = 2


  interface test_optional
    module procedure test_optional_integer_1d
    module procedure test_optional_integer_2d
    module procedure test_optional_integer_3d

    module procedure test_optional_real_1d
    module procedure test_optional_real_2d
    module procedure test_optional_real_3d
  end interface ! test_optional

  contains

  subroutine test_optional_real_1d(var1,var2)
! ---------------------------------------
! var2是可选参数;
! optional属性表示这个参数是可选的;
! 用present来判断是否传入可选参数;
! ---------------------------------------
    implicit none
    real,dimension(its:ite),intent(in) :: var1
    real,dimension(its:ite),optional,intent(in) :: var2

    print*,"var1=",var1

    if(present(var2)) then
      print*,"var2=",var2
    end if

    print*," "

  end subroutine test_optional_real_1d


  subroutine test_optional_real_2d(var1,var2)
    implicit none
    real,dimension(its:ite,jts:jte),intent(in) :: var1
    real,dimension(its:ite,jts:jte),optional,intent(in) :: var2

    print*,"var1=",var1

    if(present(var2)) then
      print*,"var2=",var2
    end if

    print*," "

  end subroutine test_optional_real_2d


  subroutine test_optional_real_3d(var1,var2)
    implicit none
    real,dimension(its:ite,jts:jte,kms:kme),intent(in) :: var1
    real,dimension(its:ite,jts:jte,kms:kme),optional,intent(in) :: var2

    print*,"var1=",var1

    if(present(var2)) then
      print*,"var2=",var2
    end if

    print*," "
    
  end subroutine test_optional_real_3d


  subroutine test_optional_integer_1d(var1,var2)
    implicit none
    integer,dimension(its:ite),intent(in) :: var1
    integer,dimension(its:ite),optional,intent(in) :: var2

    print*,"var1=",var1

    if(present(var2)) then
      print*,"var2=",var2
    end if

    print*," "

  end subroutine test_optional_integer_1d


  subroutine test_optional_integer_2d(var1,var2)
    implicit none
    integer,dimension(its:ite,jts:jte),intent(in) :: var1
    integer,dimension(its:ite,jts:jte),optional,intent(in) :: var2

    print*,"var1=",var1

    if(present(var2)) then
      print*,"var2=",var2
    end if

    print*," "

  end subroutine test_optional_integer_2d


  subroutine test_optional_integer_3d(var1,var2)
    implicit none
    integer,dimension(its:ite,jts:jte,kms:kme),intent(in) :: var1
    integer,dimension(its:ite,jts:jte,kms:kme),optional,intent(in) :: var2

    print*,"var1=",var1

    if(present(var2)) then
      print*,"var2=",var2
    end if

    print*," "
    
  end subroutine test_optional_integer_3d

END module mod_tools



program Main
  use mod_tools
  implicit none
  integer,dimension(its:ite)                 :: int_1d_1,int_1d_2
  integer,dimension(its:ite,jts:jte)         :: int_2d_1,int_2d_2
  integer,dimension(its:ite,jts:jte,kms:kme) :: int_3d_1,int_3d_2
  real   ,dimension(its:ite)                 :: real_1d_1,real_1d_2
  real   ,dimension(its:ite,jts:jte)         :: real_2d_1,real_2d_2
  real   ,dimension(its:ite,jts:jte,kms:kme) :: real_3d_1,real_3d_2

  int_1d_1 = 1
  int_1d_2 = 2

  int_2d_1 = 3
  int_2d_2 = 4

  int_3d_1 = 5
  int_3d_2 = 6

  real_1d_1 = 1.5
  real_1d_2 = 2.5

  real_2d_1 = 3.5
  real_2d_2 = 4.5

  real_3d_1 = 5.5
  real_3d_2 = 6.5


  call test_optional(int_1d_1,int_1d_2)
  call test_optional(int_2d_1,int_2d_2)
  call test_optional(int_3d_1,int_3d_2)
  call test_optional(real_1d_1,real_1d_2)
  call test_optional(real_2d_1,real_2d_2)
  call test_optional(real_3d_1,real_3d_2)


end program Main

结果

var1=           1           1           1           1
 var2=           2           2           2           2

 var1=           3           3           3           3           3           3           3           3           3           3           3           3
 var2=           4           4           4           4           4           4           4           4           4           4           4           4

 var1=           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5           5
 var2=           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6           6

 var1=   1.50000000       1.50000000       1.50000000       1.50000000
 var2=   2.50000000       2.50000000       2.50000000       2.50000000

 var1=   3.50000000       3.50000000       3.50000000       3.50000000       3.50000000       3.50000000       3.50000000       3.50000000       3.50000000       3.50000000       3.50000000       3.50000000
 var2=   4.50000000       4.50000000       4.50000000       4.50000000       4.50000000       4.50000000       4.50000000       4.50000000       4.50000000       4.50000000       4.50000000       4.50000000

 var1=   5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000       5.50000000
 var2=   6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000       6.50000000

<think>在Fortran 90中,如果你在主程序中使用一个外部子程序(例如,位于另一个文件中的函数或子例程),并且你想确保类型安全,或者子程序参数具有特殊属性(如可选的、指针、目标等),那么你需要为这个子程序提供一个接口块(interface block)。接口块允许你明确指定子程序参数类型返回类型(如果是函数),这样编译器就能进行正确的类型检查。 以下是如何声明主程序之外的文件中子程序接口的步骤: 1. 创建一个接口块(interface),在块内声明子程序的形参返回类型(如果是函数)。 2. 在主程序中使用该接口块。 注意:如果子程序在同一模块中,那么使用模块(module)来包含子程序,然后在主程序中使用该模块(use module_name)是更好的方式,这样编译器会自动生成接口。但是,如果子程序不在模块中(例如,是外部的或者放在另一个文件中的普通子程序),那么就需要显式声明接口示例: 假设我们有一个外部函数 `external_function` 定义在另一个文件中(比如 `external.f90`),该函数计算两个实数的,并返回一个实数。在主程序文件中,我们需要使用这个函数。 文件 `external.f90` 的内容: ```fortran function external_function(a, b) result(c) implicit none real :: a, b, c c = a + b end function external_function ``` 主程序文件 `main.f90` 的内容: ```fortran program main implicit none ! 声明外部函数的接口 interface function external_function(x, y) result(z) implicit none real, intent(in) :: x, y real :: z end function external_function end interface real :: a, b, c a = 5.0 b = 3.0 c = external_function(a, b) print *, 'The sum is ', c end program main ``` 解释: 1. 在主程序中,我们使用了一个接口块(interface ... end interface)来声明外部函数`external_function`的接口。 2. 在接口块内部,我们重复了函数的声明,包括参数返回值的类型。注意,我们在这里使用了`intent(in)`属性来指定参数是输入的,这有助于编译器优化检查。 3. 然后,在主程序中,我们可以像调用内部函数一样调用`external_function`。 重要提示: - 接口块必须与子程序的实际定义完全一致(包括参数的类型、顺序、属性,以及函数返回值的类型)。如果不一致,编译器可能会报错或者导致运行时错误。 - 对于子例程(subroutine),声明方式类似,只是没有返回值。 另一种情况:如果外部子程序可选参数optional),或者使用了指针、目标等属性,那么接口块中必须明确写出这些属性。 示例:带有可选参数的外部子例程 文件 `external_sub.f90`: ```fortran subroutine external_sub(a, b, c) implicit none real, intent(in) :: a real, intent(in), optional :: b real, intent(out), optional :: c if (present(b)) then if (present(c)) then c = a + b end if else if (present(c)) then c = a end if end if end subroutine external_sub ``` 主程序文件 `main.f90`: ```fortran program main implicit none ! 声明外部子例程的接口 interface subroutine external_sub(x, y, z) implicit none real, intent(in) :: x real, intent(in), optional :: y real, intent(out), optional :: z end subroutine external_sub end interface real :: a, b, c a = 5.0 b = 3.0 ! 调用方式 call external_sub(a, b, c) ! 三个参数都提供 print *, 'c = ', c call external_sub(a, c=c) ! 只提供第一个第三个参数(使用关键字参数) print *, 'c = ', c end program main ``` 注意:在接口块中,我们声明了可选参数optional)属性,这样在主程序中调用时就可以使用可选参数,并且可以使用关键字参数(如`c=c`)来指定。 使用接口块的好处是,它使得编译器能够检查调用的正确性(参数数量、类型、属性等),从而避免一些难以调试的错误。 然而,如果外部子程序很多,每个都写接口块会很繁琐。因此,Fortran 90推荐将相关的子程序放在模块中,然后通过模块来使用它们,这样编译器会自动生成接口,无需手动编写。 例如,将外部函数放在模块中: 文件 `my_module.f90`: ```fortran module my_module implicit none contains function external_function(a, b) result(c) real, intent(in) :: a, b real :: c c = a + b end function external_function end module my_module ``` 主程序文件 `main.f90`: ```fortran program main use my_module ! 使用模块,这样模块中的函数自动具有显式接口 implicit none real :: a, b, c a = 5.0 b = 3.0 c = external_function(a, b) print *, 'The sum is ', c end program main ``` 这样,通过模块使用子程序是更简洁、更安全的方式。 但是,如果你不能修改外部子程序(比如它是第三方库),那么你就需要手动编写接口块。 总结: 在Fortran 90中,为外部子程序声明接口的方法是在主程序中使用接口块(interface block)。接口块应该包含子程序的完整声明,包括所有参数返回值的类型、属性(如intent, optional, pointer等)。这样编译器就能进行类型属性检查,保证调用正确。 然而,如果可能,建议将子程序封装在模块中,然后通过use语句使用模块,这样可以自动生成接口。 §§相关问题§§: 1. 在Fortran90中,模块(module)接口块(interface)有什么区别? 2. 如何为Fortran中的外部子程序(不在模块中)编写接口块,特别是当子程序参数是数组时? 3. 在Fortran90中,使用接口块有什么性能上的影响吗? 4. 如果外部子程序参数是假定形状数组(assumed-shape array),那么在接口块中应该如何声明?</think>### 在Fortran90中声明外部子程序接口Fortran90中,当主程序需要调用外部文件中的子程序(函数或子例程)时,为了确保类型安全正确调用,需要显式声明接口块(interface block)。以下是详细解决方案: #### 解决方案代码 ```fortran ! main.f90 - 主程序文件 program main implicit none ! 声明外部子程序接口interface real function external_func(x, y) real, intent(in) :: x, y end function external_func subroutine external_sub(arr, size, flag) integer, intent(in) :: size real, dimension(size), intent(inout) :: arr logical, intent(out) :: flag end subroutine external_sub end interface ! 变量声明 real :: a = 3.0, b = 4.0, result real, dimension(5) :: array = [1.0, 2.0, 3.0, 4.0, 5.0] logical :: status ! 调用外部函数 result = external_func(a, b) print *, "Function result:", result ! 调用外部子例程 call external_sub(array, 5, status) print *, "Subroutine status:", status end program main ``` ```fortran ! external.f90 - 外部子程序文件 real function external_func(x, y) implicit none real, intent(in) :: x, y external_func = sqrt(x**2 + y**2) end function external_func subroutine external_sub(arr, size, flag) implicit none integer, intent(in) :: size real, dimension(size), intent(inout) :: arr logical, intent(out) :: flag arr = arr * 2.0 ! 数组元素翻倍 flag = all(arr > 0.0) ! 检查是否全为正数 end subroutine external_sub ``` #### 代码解释 1. **接口块声明**: - 使用`interface``end interface`关键字包裹外部子程序声明 - 精确复制子程序参数列表属性(如`intent`) - 函数需声明返回类型(如`real function`) 2. **关键属性说明**: - `intent(in)`:输入参数(不可修改) - `intent(out)`:输出参数(未初始化) - `intent(inout)`:输入输出参数(可修改) - `dimension(size)`:显式形状数组声明 3. **编译执行**: ```bash gfortran -c external.f90 # 编译外部子程序 gfortran main.f90 external.o -o program # 链接主程序 ./program # 运行程序 ``` 4. **注意事项**: - 接口声明必须与子程序实际定义完全一致 - 对于可选参数,需添加`optional`属性 - 对于指针参数,需添加`pointer`属性 - 对于字符型函数,需指定返回长度 #### 替代方案:使用模块 更推荐的方式是将子程序封装在模块中,避免手动声明接口: ```fortran ! my_module.f90 module my_module implicit none contains real function mod_func(x, y) real, intent(in) :: x, y mod_func = sqrt(x**2 + y**2) end function subroutine mod_sub(arr, flag) real, dimension(:), intent(inout) :: arr logical, intent(out) :: flag arr = arr * 2.0 flag = all(arr > 0.0) end subroutine end module ! main.f90 program main use my_module ! 自动包含接口 real :: arr(5) = [1,2,3,4,5] logical :: flag print *, mod_func(3.0, 4.0) ! 输出 5.0 call mod_sub(arr, flag) end program ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值