0

我编写了一个模块,其中包含一个名为“push”的接口,该接口将值推送到可分配数组中。我希望它具有通用行为,以便我可以根据需要将给定类型的新函数添加到“推送”接口。问题在于,随着给定接口的函数数量增加,推送接口的奇怪行为也在增加。

模块代码(push_array.f90):

module push_array
  implicit none
  ! usage:
  ! array = push(array,val)
  interface push
     module procedure push_scalar_int_onto_rank1_int
     module procedure push_scalar_int2_onto_rank1_int2
     module procedure push_rank1_int_onto_rank2_int
     module procedure push_rank1_real8_onto_rank2_real8
  end interface push

contains
  function push_scalar_int_onto_rank1_int (array,val) result (new_array)
    integer,intent(in),allocatable :: array(:)
    integer,intent(in) :: val
    integer,allocatable :: new_array(:)
    integer :: length
    if (allocated(array)) then
       length = size(array) + 1
    else
       length = 1
    end if
    allocate(new_array(size(array) + 1))
    if (allocated(array)) new_array(:) = array(:)
    new_array(length) = val
    return
  end function push_scalar_int_onto_rank1_int

  function push_scalar_int2_onto_rank1_int2 (array,val) result (new_array)
    integer(2),intent(in),allocatable :: array(:)
    integer(2),intent(in) :: val
    integer(2),allocatable :: new_array(:)
    integer :: length
    if (allocated(array)) then
       length = size(array) + 1
    else
       length = 1
    end if
    allocate(new_array(size(array) + 1))
    if (allocated(array)) new_array(:) = array(:)
    new_array(length) = val
    return
  end function push_scalar_int2_onto_rank1_int2

  function push_rank1_int_onto_rank2_int (array,val) result (new_array)
    integer,intent(in),allocatable :: array(:,:)
    integer,intent(in) :: val(:)
    integer,allocatable :: new_array(:,:)
    integer :: length
    if (allocated(array)) then
       length = size(array,2) + 1
    else
       length = 1
    end if
    allocate(new_array(1:size(val),length))
    if (allocated(array)) new_array(1:size(val),:) = array(1:size(val),:)
    new_array(1:size(val),length) = val
    return
  end function push_rank1_int_onto_rank2_int

    function push_rank1_real8_onto_rank2_real8 (array,val) result (new_array)
    real(8),intent(in),allocatable :: array(:,:)
    real(8),intent(in) :: val(:)
    real(8),allocatable :: new_array(:,:)
    integer :: length
    if (allocated(array)) then
       length = size(array,2) + 1
    else
       length = 1
    end if
    allocate(new_array(1:size(val),length))
    if (allocated(array)) new_array(1:size(val),:) = array(1:size(val),:)
    new_array(1:size(val),length) = val
    return
  end function push_rank1_real8_onto_rank2_real8

end module push_array

测试代码(test_push_array.f90):

program main
  use push_array, only: push
  implicit none
  integer,allocatable :: a(:)
  integer(2),allocatable :: b(:)
  integer,allocatable :: c(:,:)
  real(8),allocatable :: d(:,:)
  integer :: xp(3)
  real(8) :: xp8(3)
  integer :: i
  integer(2) :: j
  ! test that a scalar integer can be pushed onto a rank1 integer array
  do i=1,100
     a = push(a,i)
  end do
  print *, a(1),a(100)

  ! test that a scalar integer(2) can be pushed onto a rank1 integer(2) array
  do j=1,100
     b = push(b,j)
  end do
  print *, b(1),b(100)

  ! test that a rank1 integer can be pushed onto a rank2 integer
  do i=1,100
     xp = [i,i+1,i+2]
     c = push(c,xp)
  end do
  print *, c(1:3,1),c(1:3,100)

  ! test that a rank1 real(8) can be pushed onto a rank2 real(8)
  do i=1,100
     xp8 = [i + 0.001,i + 0.002, i + 0.003]
     d = push(d,xp8)
  end do
  print *, d(:,1),d(:,100)

end program main

输出以显示编译器标志:

$ make
gfortran -g -O2 -c push_array.f90
gfortran -g -O2 -o main test_push_array.f90 push_array.o

我的编译器版本:

$ gfortran --version
GNU Fortran (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.

我的系统:

$ uname -a
Darwin darthan 12.5.0 Darwin Kernel Version 12.5.0: Sun Sep 29 13:33:47 PDT 2013; root:xnu-2050.48.12~1/RELEASE_X86_64 x86_64

如果我按照给定的方式运行测试代码,它将进入无限循环并且我的系统内存完全耗尽。我试图通过设置断点来跟踪 gdb 中的测试用例,在第一个循环中我将 i 推到 a 上,但 gdb 无法进入模块函数。

如果我只评论我被推到 a 的第一个测试循环,结果如下:

$ ./main
      1    100
           1           2           3         100         101         102
   1.0010000467300415        1.0019999742507935        1.0030000209808350        100.00099945068359        100.00199890136719        100.00299835205078     

这些都是意料之中的。

如果我只注释掉将 j 推到 b 上的第二个循环,结果如下:

$ ./main
           1         100
           1           2           3         100         101         102
   1.0010000467300415        1.0019999742507935        1.0030000209808350        100.00099945068359        100.00199890136719        100.00299835205078     

再一次,正如预期的那样。

当我注释掉将 xp 推送到 c 的第三个循环时,事情开始变得奇怪:

$ ./main
           1           0
      1      0
   1.0010000467300415        1.0019999742507935        1.0030000209808350        100.00099945068359        100.00199890136719        100.00299835205078     

当我注释掉我将 xp8 推到 d 上的第四个循环时,模式继续:

$ ./main
           1           0
      1      0
           1           2           3         100         101         102

我的问题:

  1. 当我尝试在同一个程序中使用推送接口中定义的所有四个函数时,为什么主测试程序会进入死循环?

  2. 在我注释掉第三个和第四个循环的情况下,为什么 a(100) 和 b(100) 的结果都等于 0?

任何反馈将不胜感激...谢谢!

编辑:

下面给出需要更改的两个函数

  function push_scalar_int_onto_rank1_int (array,val) result (new_array)
    integer,intent(in),allocatable :: array(:)
    integer,intent(in) :: val
    integer,allocatable :: new_array(:)
    integer :: length
    if (allocated(array)) then
       length = size(array) + 1
    else
       length = 1
    end if
    allocate(new_array(length)) ! changed
    if (allocated(array)) new_array(:) = array(:)
    new_array(length) = val
    return
  end function push_scalar_int_onto_rank1_int

  function push_scalar_int2_onto_rank1_int2 (array,val) result (new_array)
    integer(2),intent(in),allocatable :: array(:)
    integer(2),intent(in) :: val
    integer(2),allocatable :: new_array(:)
    integer :: length
    if (allocated(array)) then
       length = size(array) + 1
    else
       length = 1
    end if
    allocate(new_array(length)) ! changed
    if (allocated(array)) new_array(:) = array(:)
    new_array(length) = val
    return
  end function push_scalar_int2_onto_rank1_int2
4

2 回答 2

1

您在某些函数体中的 allocate 语句引用了array参数的大小。如果array未分配参数,则该引用无效。

在程序的前面,您测试分配状态并设置一个名为的变量length- 也许您打算使用它。

(为了清楚起见——也许看看push_scalar_int_onto_rank1_int函数中的 allocate 语句。)

于 2014-03-10T22:39:30.117 回答
1

IanH 解释了这个问题。编译器可以帮助您找到它。根据编译选项,我从 gfortran 4.8 得到不同的响应。用-O2 -fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -fcheck=all -std=f2008 -pedantic -fbacktrace它编译,然后给出运行时错误:

At line 25 of file push.f90
Fortran runtime error: Index '1' of dimension 1 of array 'new_array' above upper bound of -265221874

第 25 行是 in 之前的returnpush_scalar_int_onto_rank1_int

于 2014-03-10T23:28:25.543 回答