在Fortran中使用数组成员作为do循环的控制变量

5

我很惊讶你不能像这样将数组成员作为do循环的控制变量:

program test
    integer, dimension(2) :: i 

    do i(1) = 1, 3
    do i(2) = 1, 3
        ! anything here
        write(*, *) i
    end do
    end do
end program

我的问题是为什么不被允许?

编辑: 或者它是被允许的,但我做错了吗?

ifort v 11.1 的错误信息是:

test.f90(4): error #5082: Syntax error, found IDENTIFIER 'I' when expecting one of: ( % : . = =>
    do i(1) = 1, 3
-------^
test.f90(4): error #5082: Syntax error, found ',' when expecting one of: <END-OF-STATEMENT> ;
    do i(1) = 1, 3
---------------^
test.f90(5): error #5082: Syntax error, found IDENTIFIER 'I' when expecting one of: ( % : . = =>
    do i(2) = 1, 3
-------^
test.f90(5): error #5082: Syntax error, found ',' when expecting one of: <END-OF-STATEMENT> ;
    do i(2) = 1, 3
---------------^
test.f90(4): error #6535: This variable or component must be of a derived or structure type   [DO]
    do i(1) = 1, 3
----^
test.f90(4): error #6460: This is not a field name that is defined in the encompassing structure.   [I]
    do i(1) = 1, 3
-------^
test.f90(8): error #6099: An ENDDO statement occurred without a corresponding DO or DO WHILE statement.
    end do
----^
test.f90(9): error #6099: An ENDDO statement occurred without a corresponding DO or DO WHILE statement.
    end do
----^
test.f90:4.4:

    do i(1) = 1, 3
    1
Error: Unclassifiable statement at (1)
test.f90:5.4:

    do i(2) = 1, 3
    1
Error: Unclassifiable statement at (1)
test.f90:8.7:

    end do
       1
Error: Expecting END PROGRAM statement at (1)
test.f90:9.7:

    end do
       1
Error: Expecting END PROGRAM statement at (1)
3个回答

7

Vladimir F的答案是正确的,但我们可以更加强调相关点。

关于do变量的引用语法规则为:

R819 do-variable is scalar-int-variable-name

非常重要的一点是确切理解这意味着什么。

当然,do变量必须是一个标量整数变量。在本问题中,数组元素i(1)(以及i(2))是一个标量整数变量:数组元素是秩为0的变量。

然而,name是一个进一步的限制。i(1)本身不是一个名称。我们看到以下语法规则:

R303 name is letter [ alphanumeric-character ] ...

这个超出了标量整数变量的限制范围。此外,以下内容可能是没有相应名称的变量:

  • 派生类型的组件;
  • 具有指针结果的函数(Fortran 2008之前不是变量)。

这意味着以下操作是不允许的:

type t
  integer i
end type t
type(t) x

do x%i=1,1   ! x%i is not a name
end do

end

同样也不是

integer, target :: i
do f()=1,1
end do

contains
  function f()
    integer, pointer :: f
    f=>i
  end function
end

然而,正如chw21的答案中所指出的那样,使用关联构造是成功的:

type t
  integer i
end type
type(t) x
integer n(1)

associate (i=>x%i, j=>n(1))
  do i=1,1
    do j=1,1
    end do
  end do
end associate
end

尽管x%in(1)不是名称,但associate结构确实创建了名称:

R803 associate-stmt [associate-construct-name :] ASSOCIATE (association-list)

R804 association associate-name => selector

请注意,仅将关联实体作为变量是不够的。
同样,如果有名称,则允许指针
type t
  integer i
end type
type(t), target :: x
integer, target :: n(1)

integer, pointer :: i, j

i => x%i
j => n(1)

do i=1,1
  do j=1,1
  end do
end do
end

这里的ij是变量名。

有趣的是,NAG编译器将使用指针和关联实体的标记视为“可疑”。事实上,我们必须额外小心,以避免更改循环变量。


6

对于我第一个错误的答案,我感到抱歉。

这个限制是由该语言规则所决定的:

Fortran 2008 (ISO/IEC 1539-1:2010) 8.1.6.2:

R818 loop-control is, do-variable = ...

R819 do-variable is, scalar-int-variable-name

C812 (R819) 循环变量必须是整数型变量。

因此,在循环控制变量的位置上只允许使用标量变量名。

如果你问为什么语言规则是这样的,那么你需要问标准的作者SC22/WG5和X3J3,但是我猜这可能与固定源代码形式中语法清晰度的必要性有关。在固定源代码形式中,空格并不重要,难以想出一种明确的语法。


由于这主要是语法问题,你认为最好的解决方法是什么?(例如使用手动增量的do while循环,为每个步骤分配数组,如果可能的话使用指针) - user3136376
三种方法都可以使用。选择哪一种取决于编码风格和具体的代码片段。 - Vladimir F Героям слава

5

Fortran 2003及以后版本有一个名为"Associate block"的结构,你可以在这个结构内将任何表达式与一个名称相关联。在你的情况下,它看起来有点像这样:

program test
    integer, dimension(2) :: i

    associate (x => i(1), y => i(2))
        do x = 1, 3
        do y = 1, 3
            ! anything here
            write(*, *) i
        end do
        end do
    end associate
end program

这会更新双重循环中的 i
(注意:在 @VladimirF 在下面的评论中确认之前,我不确定这是否符合标准。谢谢)

这正是我昨天回到这里后想知道的。不确定 associate-name 是否允许在这里,但也许它是被允许的,只是我找不到它。 - Vladimir F Героям слава
1
是的 F2018:11.1.3.3.5 关联实体本身是一个变量... 相对于 F2008,这更明确和清晰。 - Vladimir F Героям слава
当然可以,但我有疑问,这是否真的是一个变量。从F2008文本中并不清楚。 - Vladimir F Героям слава

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接