Это ошибка в компиляторе, и она по-прежнему стоит в gfortran v9.0.0 (experimental)
в Windows.Вы должны сообщить об этом поставщику .
Я провел несколько тестов, и кажется, что сбой только происходит, когда: передает существующий необязательный аргументкак фактический аргумент, соответствующий фиктивному аргументу, который character(:), allocatable, optional
.Кажется, что любое изменение в предыдущем предложении позволяет избежать ошибки и дает правильный результат.
Я сократил ваш пример до минимального контрольного примера:
program main
implicit none
character(:), allocatable :: txt
call sub1(txt)
print *, "main ", len(txt), txt ! prints: main 0 (or throws segfault)
contains
subroutine sub1(txt)
character(:), allocatable, optional :: txt
call sub2(txt)
print *, "sub1 ", len(txt), txt ! prints: sub1 0 (or throws segfault)
end
subroutine sub2(txt)
character(:), allocatable, optional :: txt
if(present(txt)) txt = "message"
print *, "sub2 ", len(txt), txt ! prints: sub2 7 message
end
end
Проверка внутри sub2
показываетчто назначение на самом деле работает там.Кажется, проблема возникает, когда этот фиктивный объект сопоставляется с фактическим аргументом внутри sub1
.Хм ...
Опять же, любое изменение шаблона character(:), allocatable, optional
манекенов дает правильный результат в моих тестах.Итак, я предлагаю вам гибко настроить хотя бы одно из предыдущих условий, чтобы обойти глючную вещь.Есть несколько предложений:
1.неразмещаемый необязательный символ работает , независимо от того, фиксированная или предполагаемая длина;
Вот пример с переменной фиксированной длины и аргументами предполагаемой длины.
Преимущество : Легко реорганизовать, менее разрушительно / навязчиво.
Недостаток : Необходимо заранее оценить длину переменной, хранение отходов.
program option1
implicit none
character(10) :: txt
call sub1(txt)
print *, "main ", len(txt), txt ! prints: main 10 message
contains
subroutine sub1(txt)
character(*), optional :: txt
call sub2(txt)
print *, "sub1 ", len(txt), txt ! prints: sub1 10 message
end
subroutine sub2(txt)
character(*), optional :: txt
if(present(txt)) txt = "message"
print *, "sub2 ", len(txt), txt ! prints: sub1 10 message
end
end
2. необязательно для фактического аргумента, переданного из sub1
или для фиктивного аргумента в sub2
, также заставляет его работать ;
Конечно, если вы можете реорганизовать свой код, чтобы избежать этой ситуации, это было бы лучшим решением.Например, вы можете использовать общие интерфейсы для достижения аналогичного результата.Или, как вы сказали в комментарии: « с использованием локальных переменных на уровне 1 и передачей всех необязательных аргументов на нижний уровень ».
Недостаток : может потребоватьсяизменить интерфейсы процедур нижнего уровня.
Преимущество : не будет проблем, если они являются процедурами частного модуля;Это деталь реализации.
Рассмотрим следующий подход, который взламывает ошибку и избегает передачи необязательного аргумента, поэтому не меняет сигнатуру процедуры :
program option2
implicit none
character(:), allocatable :: txt
call sub1(txt)
print *, "main ", len(txt), txt ! prints: main 7 message
contains
subroutine sub1(txt)
character(:), allocatable, optional :: txt
character(:), allocatable :: txt_
if(present(txt)) then
! txt_ isn't optional, so the bug doesn't fire
call sub2(txt_)
txt = txt_
end if
print *, "sub1 ", len(txt), txt ! prints: sub1 7 message
end
subroutine sub2(txt)
character(:), allocatable, optional :: txt
print *, present(txt)
if(present(txt)) txt = "message"
print *, "sub2 ", len(txt), txt ! prints: sub2 7 message
end
end
3. с любым другим типом тоже работает , независимо от атрибутов (даже производного типа с выделяемым символьным компонентом).Хотя изменения в ранге или типе не учитываются.
Я покажу вам два варианта, связанных с производными типами: один с выделяемым компонентом длины символа;другой с параметризованным производным типом.
Advantage : Вы можете сохранить свою структуру кода и все дополнительные компоненты.Объем хранения невелик.Вы даже можете расширить свой DT с помощью методов и адаптировать его к вашей проблеме.
Недостаток : Возможно, слишком много хлопот для мало.PDT - это круто, но это новая (и глючная) функция в gfortran.
program option3a
! using a derived type with allocatable character length component.
implicit none
type :: string
character(:), allocatable :: chars
end type
type(string) :: txt
call sub1(txt)
print *, "main ", len(txt%chars), txt%chars ! prints: main 7 message
contains
subroutine sub1(txt)
type(string), optional :: txt
call sub2(txt)
print *, "sub1 ", len(txt%chars), txt%chars ! prints: sub1 7 message
end
subroutine sub2(txt)
type(string), optional :: txt
if(present(txt)) txt = string("message")
print *, "sub2 ", len(txt%chars), txt%chars ! prints: sub2 7 message
end
end
program option3b
! using a parameterized derived type, you can practically mimic the intrinsic
! character type behavior, with the possibility to add custom behavior.
! but its still raw in gfortran.
implicit none
type :: string(len)
integer, len :: len
character(len) :: chars
end type
type(string(:)), allocatable :: txt
call sub1(txt)
print *, "main ", txt%len, txt ! prints: main 7 7 message (a lil bug of gfortran)
contains
subroutine sub1(txt)
type(string(:)), allocatable, optional :: txt
call sub2(txt)
print *, "sub1 ", txt%len, txt ! prints: main 7 7 message
end
subroutine sub2(txt)
type(string(:)), allocatable, optional :: txt
! the following fails with gfortran, however it's valid syntax
! if(present(txt)) txt = string(7)("message")
allocate(string(7) :: txt)
if(present(txt)) txt%chars = "message"
print *, "sub2 ", txt%len, txt ! prints: main 7 7 message
end
end
Подводя итог: вы можете изменить свой компилятор или выбрать любой из этих (или других) способов обойти эту ошибкуи продолжайте работать до тех пор, пока поставщик вашего компилятора не решит проблему.