【问题标题】:Non-one indexed array from associate来自关联的非一个索引数组
【发布时间】:2021-04-20 09:41:44
【问题描述】:

我希望有一个指向数组(或其部分)并且不是索引的关联。 下面的程序说明了这个问题:

program test_associate
    implicit none(type, external)
    integer, parameter :: N = 10
    integer :: i, A(0 : N - 1)

    A = [(i, i = lbound(A, 1), ubound(A, 1))]
    write(*, *) A(0), A(9)

    associate(B => A(0 : N - 1))
        write(*, *) B(9)    ! This writes 8 but should write 9
    end associate
end program

我试过了

    associate(B(0 : N - 1) => A(0 : N - 1))
        write(*, *) B(9)
    end associate

但这是无效的语法。 (至少在我的 gfortran 9.3 编译器中)

【问题讨论】:

    标签: fortran fortran2003


    【解决方案1】:

    语法

    associate (B(0:N-1) => ...)
    end associate
    

    在 Fortran 中无效:关联项的左侧必须是 名称。仅使用名称(此处为 B)无法指定诸如边界之类的属性。

    关联实体数组的边界(同样,这里是 B)由在右侧使用 LBOUND 的结果(选择器)给出(Fortran 2018, 11.1.3.3 第 1 页):

    每个维度的下界是内在函数LBOUND(16.9.109)应用于选择器的对应维度的结果

    LBOUND 的引用描述解释了在这种情况下如何计算边界。

    因为A(0:N-1) 不是一个完整的数组,所以LBOUND 返回1,因此在这种情况下B 的下限本身就是1

    B 的下限可能不是1:选择器是一个完整的数组。在

    associate(B => A)
    end associate
    

    B 将具有A 的下限。

    结论:关联实体可能具有除1 之外的下限,但仅当它关联的事物是整个数组时。特别是,在与数组的一部分(并且可以包括数组的所有,例如B => A(:)A(:) 不是整个数组)关联时,关联实体始终具有下限@ 987654340@.

    正如 Vladimir F 在另一个答案中所说,指针的边界可以作为指针分配的一部分进行控制。

    【讨论】:

    • 从您的回答中,我看到我的最小示例太小了。在我的实际代码中,我的排名高于 1,并使用 associate 指向一行。类似于此语句associate(row => A(0 : N, i, j)) 在这种情况下,我的 rhs 表达式永远不会是一个完整的数组,所以我总是会得到一个单索引关联实体数组? (当然,除非我在弗拉基米尔的回答中使用指针。)
    • 确实:没有办法只选择许多维度的一维,仍然有一个完整的数组。在这种情况下,您将被 1-indexing 卡住。出于“为某些可怕的引用提供新的方便名称”以外的原因与整个数组相关联是非常罕见的,因此通常情况下您将拥有 1 索引。
    • 您可能会发现call work_on_row(row=A(0:N,i,j),lbound=0) 更有帮助,而不是使用指针而不是关联结构。如果由于必须处理非默认边界而使 associate 构造中的内容变得复杂,那么有一个论点是将这项工作放入过程中是有帮助的。
    【解决方案2】:

    我认为这是不可能的。 A(0 : N - 1) 是一个子数组,它是一个表达式,不再是原来的数组。 A(0 : N - 1) 的下限是 1,而不是 0。

    你可以试试

    dimension A(0:9)
    print *,lbound(A(0:8))
    end
    

    它将打印1

    请注意,您的同事可能会将数组部分复制并存储在临时数组中。

    如果你关联到=> BA 会正确写成9

    您可以使用指针指向这些部分

    program test_associate
        implicit none(type, external)
        integer, parameter :: N = 10
        integer, target :: A(0 : N - 1)
        integer, pointer :: B(:)
        integer :: i
    
        A = [(i, i = lbound(A, 1), ubound(A, 1))]
        write(*, *) A(0), A(9)
        
        B(0:N-1) => A(0:N-1)
        write(*, *) B(9)    ! This writes 9
    
    end program
    

    【讨论】:

    • i 必须是目标吗? PS:很抱歉没有正式接受你的回答,如果我能接受,我很乐意接受。
    • @mcocdawc 确实如此。你可以接受任何你想要的答案。我没有解决编译器错误的原因(语法无效),只是边界问题以及如何解决。
    • 但是i 永远不会被任何指针指向,并且如果i 不是目标,它至少会在启用gfortran 和所有警告的情况下进行编译。
    • @mcocdawc 当然,我没有检查您询问的符号名称。指向的数组必须是目标。没有其他的。可能我快速更改您的代码让您感到困惑。
    猜你喜欢
    • 2017-03-28
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-10
    相关资源
    最近更新 更多