以下MWE描述了我想要使用的内容(请注意,我没有设计这个,我只是尝试使用某些代码,我通常不会使用全局变量)。
PROGRAM MAIN
IMPLICIT NONE
integer :: N
real(8), allocatable :: a(:,:)
N=3
allocate(a(N,3))
a=initialize_array()
CONTAINS
function initialize_array() result(a)
IMPLICIT NONE
real(8) :: a(N,3)
a=1
end function initialize_array
END PROGRAM MAIN
gfortran给出一个错误,该错误读取Error: Variable 'n' cannot appear in the expression at (1)
,指向函数内的real(8) :: a(N,3)
。
在一个子程序中它会起作用,那么这里可能出现什么问题呢?
为什么ifort(v.15.0.3)编译这个,而gfortran(v.4.8.4)不编译?
答案 0 :(得分:5)
正如其他人评论的那样,很难说某些事情是否被明确允许:语言主要基于规则和限制条件。
所以,我不会证明代码没有错误(并且gfortran不允许拒绝它),但是让我们来看看发生了什么。
首先,我会反对High Performance Mark给出的一件事,因为这有点相关:
具有依赖于变量值的维度的数组的声明,例如
a(N,3)
,要求在编译时知道(或至少可知)变量的值。
显式形状数组的边界不必总是由常量表达式给出(我们松散地定义为“在编译时已知/可知”):在某些情况下,显式形状数组可以具有变量给出的界限。这些被称为自动对象(以及规范表达式给出的界限)。
功能结果是允许自动对象的一个地方。在函数结果声明的问题示例中,N
与主机关联并形成规范表达式。
让我们看看gfortran如何回应程序的小修改,而不是用尽所有其他约束来看到a
的声明是真的被允许的。
首先,gfortran对象的问题代码的修剪版本。
integer n
contains
function f() result(g)
real g(n)
end function f
end program
f
的功能结果名称为g
。我们称之为函数结果并不重要,所以当我们称之为f
时会发生什么?
integer n
contains
function f()
real f(n)
end function f
end program
这对我来说很愉快。
如果我们在模块而不是主程序中构建第一个块会怎么样?
module mod
integer n
contains
function f() result(g)
real g(n)
end function f
end module
那也是编译。
自然的结论:即使gfortran是正确的(我们已经错过了一些隐藏得很好的约束)来拒绝第一个代码,它要么在不拒绝其他代码时非常不一致,要么约束真的很奇怪。
答案 1 :(得分:1)
我认为这可能是一个解释,虽然像@VladimirF我实际上无法回想起或找到标准的相关部分(如果有的话)。
这一行
real(8) :: a(N,3)
声明函数的结果是一个名为a
的数组。这掩盖了主机关联引用数组a
的相同名称的可能性。函数范围内的a
不是程序范围中的a
。
具有依赖于变量值的维度的数组的声明,例如a(N,3)
,要求在编译时知道(或至少可知)变量的值。在这种情况下,在主机范围内提供n
,属性parameter
可以解决问题。虽然它并没有解决这个糟糕的设计 - 但是OP的手似乎与这一点有关。
英特尔编译器编译它并不让我感到惊讶,它编译了它的祖先多年来为了向后兼容而编译的各种怪异。
我只提供这个半生不熟的解释,因为经验告诉我,一旦我做了一个真正的Fortran专家(IanH,francescalus,(通常)VladimirF)会因为发布更正而感到愤怒,我们&# 39;所有人都学到了什么。