在Fortran中使用全局变量时出现错误的结果

时间:2017-02-03 12:40:26

标签: fortran fortran90

我正在学习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

编译了程序

2 个答案:

答案 0 :(得分:5)

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

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

子程序可以“查看”父模块的其他变量(如果它是模块过程),或父变量(主机)过程或程序的变量(如果它是内部过程)。

请务必阅读Fortran程序的结构并尽可能使用模块。优先于内部程序的模块。您将看到如何将子例程放入模块或如何将其作为链接中主程序的内部。

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

答案 1 :(得分:1)

假设你想要它到处都是,那么在f77时代使用COMMON块,现在使用MODULE。

我对大部分变化进行了大写。如果没有错误提供了一些方法来考虑在SUBROUTINE中理解N,那么元素功能也可能值得在这里尝试。

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