在被调用的子例程/函数中强制Fortran中的intent(in)声明变量也是常量

Ric*_*wig 6 fortran

在子例程或函数中,可以使用intent(in)定义输入变量,并且编译器确保在子例程内不能更改变量.一旦变量(通过引用)传递给另一个子例程,该子例程就能够在没有编译器警告的情况下更改变量.

这是用gfortran测试的代码:

program Test
    integer i
    i = 21 ! half the truth
    call test(i)
    write (*,*) "21 expected, but is 42: ", i
end program

subroutine test(i)
    integer, intent(in) :: i
    call doSomethingNasty(i)
end subroutine

subroutine doSomethingNasty(i)
    integer :: i
    i = 42 ! set the full truth ;-)
end subroutine
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 这是所有编译器的正常行为吗?
  2. 有没有办法强制编译器确保变量是真正的常量,并且更改将表示为编译器错误?我的意思是类似于C/C++中的const关键字,它也会根据被调用函数进行检查,这也需要确保相应地处理常量并且没有引用转义.
  3. 我发现有可能通过"值"将变量传递给子程序,方法是将其传递给类似的表达式test((i)).对于数值变量,这是可以理解的,但是这似乎也适用于gfortran的数组,派生类型和指针.这也适用于其他编译器吗?这是保护我的局部变量的安全方法吗?

M. *_* B. 8

使用足够的编译器选项,gfortran会为您的示例生成警告,即使用隐式接口.

如果通过将子例程放入模块中使接口显式化,并对所有参数使用intent,gfortran将捕获问题:

module mysubs

contains

subroutine test(i)
    integer, intent(in) :: i
    call doSomethingNasty(i)
end subroutine

subroutine doSomethingNasty(i)
    integer, intent (inout) :: i
    i = 42 ! set the full truth ;-)
end subroutine


end module mysubs


program Test_intent_in

use mysubs

    integer i
    i = 21 ! half the truth
    call test(i)
    write (*,*) "21 expected, but is 42: ", i

end program Test_intent_in
Run Code Online (Sandbox Code Playgroud)

gfortran给出错误消息:

call doSomethingNasty(i)
                          1
Error: Procedure argument at (1) is INTENT(IN) while interface specifies INTENT(INOUT)
Run Code Online (Sandbox Code Playgroud)

传递参数"(i)"时,您传递的是表达式而不是变量.表达式不可定义,因此不应用作"out"或"inout"伪参数的实际参数.

参数"安全"的另一种方法:您还可以在伪参数的声明中使用"value"属性来基本上创建参数的本地副本,并保证实际参数不会被更改.

编辑:正如kemiisto指出的那样,"包含"也使得界面已知.我不喜欢"包含",因为变量作用域...父程序的所有变量都是可见的.试试这个测试代码:

PROGRAM contains_tst

  INTEGER :: i, m

  i = 21
  m = 22
  CALL test(m)

  CONTAINS

    SUBROUTINE test(j)
      INTEGER, INTENT(IN) :: j
      write (*, *) i, j
    END SUBROUTINE test

END PROGRAM contains_tst
Run Code Online (Sandbox Code Playgroud)

  • 如果接口不是"显式",则编译器不"知道"接口,也不检查调用者和被调用者之间的一致性.这是一个INTER程序检查的问题.使接口显式化的最简单方法是将过程放入模块中.(您可以使用接口语句,但这更容易发生工作并且容易出错.)将程序放在模块中允许编译器进行大量的一致性检查 - 这对程序员来说是一个很大的帮助!如果不指定intent,则参数用法可能正常,因此使用不是错误. (5认同)