【问题标题】:Wrong result when using a global variable in Fortran在 Fortran 中使用全局变量时结果错误
【发布时间】:2017-06-20 20:14:19
【问题描述】:

我正在学习 Fortran 的基础知识。我创建了一个初始化矩阵的简单子程序:

program test
   integer, parameter :: n = 1024
   real :: a(n, n)
   call init(a)
   write (*, *) a(1, 1)
end program

subroutine init(a)
   real :: a(n, n)
   a(:, :) = 3.0
end subroutine

那么输出是0.0,而不是预期的3.0。除此之外,valgrind 表示:

==7006== Conditional jump or move depends on uninitialised value(s)
==7006==    at 0x400754: init_ (in /home/marcin/proj/mimuw/fortran/test)
==7006==    by 0x4007A4: MAIN__ (in /home/marcin/proj/mimuw/fortran/test)
==7006==    by 0x40083B: main (in /home/marcin/proj/mimuw/fortran/test)

为什么? n 参数被编译器正确识别,应该是全局的。

我用 gfortran 6.3.1 编译了程序

【问题讨论】:

  • 也许您正在考虑一个内部程序。
  • n 不是全局对象。如果你在子程序中添加implicit none,你会看到一个错误。
  • 哦,所以我在子程序中也需要implicit none!不知道。在测试时,我尝试在program 中使用它,但在subroutine 中没有。是否可以全局使用implicit none
  • 由于各种程序单元的独立编译性质(正如 Vladimir F 所提到的),没有真正意义上的“全局”范围界定。您可以在this question 中找到有关隐式类型规则的详细信息。

标签: fortran fortran90


【解决方案1】:

n不是全局变量,是主程序的局部变量。

子程序是一个完全独立于主程序的编译单元,它们不共享任何信息。

一个子程序可以“看到”父模块的其他变量,如果它是一个模块程序,或者如果它是一个内部程序的话,它可以是一个父(宿主)程序或程序的变量。

请务必阅读 Fortran 程序的结构并尽可能多地使用模块。更喜欢模块而不是内部过程。您将在链接中看到如何将子例程放入模块或如何将其置于主程序的内部。

我没有提到常见的块,只是不要使用它们,它们已经过时了。请记住在每个编译单元中使用implicit none

【讨论】:

  • 所以n 只是在我在子例程中使用时隐式声明的?
  • @marmistrz 是的,隐式键入以 i,n 和其他一些字母开头的所有内容(甚至不记得哪些字母)被声明为整数。通常你不应该使用隐式类型,因为这有时会导致不希望的行为。我可以建议阅读 Michael Metcalf 的 Modern Fortran Explained - 这可以帮助您完成入职流程。
【解决方案2】:

假设你想要它无处不在,那么在 f77 时代使用一个 COMMON 块,现在使用一个 MODULE。

我对大部分更改进行了大写。如果没有错误,给出了一些考虑理解子程序中的 N 的方法,并且在这里也可能值得尝试一个 ELEMENTAL FUNCTION。

MODULE MyMODULE
  integer, parameter :: n = 1024
END MODULE MyMODULE

!%%%%%%%%%% 
program test
USE MyModule
IMPLICIT NONE
! done up in ˆmoduleˆ...!  integer, parameter :: n = 1024
REAL, DIMENSION(n,n) :: A

CALL Alternative_Init(A, 3.3)
WRITE (*,*) a(1, 1)

CALL Alternative2_Init(A, n, 1.23)
WRITE (*,*) a(1, 1)

call init(a)
write (*, *) a(1, 1)
END PROGRAM TEST

!%%%%%%%%%% 
subroutine init(a)
USE MyModule
IMPLICIT NONE

real :: a(n, n)
a(:, :) = 3.0

RETURN
END SUBROUTINE init


!%%%%%%%%%% 
SUBROUTINE Alternative_Init(a, Val4A)
USE MyModule
IMPLICIT NONE

REAL, DIMENSION(:,:) , INTENT(INOUT) :: a
REAL                 , INTENT(IN  )  :: Val4A

a(:, :) = Val4A
! or just... A = Val4A ! which does them all too.

RETURN
END SUBROUTINE Alternative_Init

!%%%%%%%%%% 
SUBROUTINE Alternative2_Init(a, n, Val4A)
!!!!  USE MyModule
IMPLICIT NONE

INTEGER              , INTENT(IN   ) :: n
REAL, DIMENSION(n,n) , INTENT(  OUT) :: a
REAL                 , INTENT(IN   ) :: Val4A

A = Val4A

RETURN
END SUBROUTINE Alternative2_Init

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    • 2018-10-22
    相关资源
    最近更新 更多