Почему этот интерфейс модуля Fortran дает разные результаты в зависимости от того, сколько его функций используется?

Я написал модуль, который содержит интерфейс "push", который помещает значения в размещаемые массивы. Я хочу, чтобы он имел общее поведение, чтобы при необходимости я мог добавить новую функцию для заданного типа в интерфейс push. Проблема заключается в том, что с ростом количества функций для данного интерфейса происходит странное поведение 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. Почему основная тестовая программа заходит в бесконечный цикл, когда я пытаюсь использовать все четыре функции, определенные в интерфейсе push, в одной программе?

  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

2 ответа

Решение

Вы размещаете оператор в некоторых телах функций, ссылаясь на размер array аргумент. Если array Аргумент не выделен, эта ссылка недействительна.

Ранее в процедуре вы проверяли статус распределения и устанавливали переменную с именем length - возможно, вы хотели использовать это.

(Для ясности - возможно, посмотрите на утверждение allocate в push_scalar_int_onto_rank1_int функция).

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 - это строка перед return в push_scalar_int_onto_rank1_int,

Другие вопросы по тегам