Я передаю необязательные строки с отложенной длиной (character(len=:), allocatable, optional
) между подпрограммами и получаю неожиданное поведение в G CC.
Вот мой минимальный пример, где я передаю необязательную строку через процедуру интерфейса к подпрограмме, которая устанавливает его:
$ cat main.f90
module deepest_call_m
implicit none
contains
subroutine deepest_call(str)
character(len=:), allocatable, intent(OUT), optional :: str
if (present(str)) str = '12345'
write(*,*) 'at bot of deepest_call, str is "'//trim(str)//'"'
end subroutine deepest_call
end module deepest_call_m
module interface_call_m
implicit none
contains
subroutine interface_call(str)
use deepest_call_m, only : deepest_call
character(len=:), allocatable, intent(OUT), optional :: str
call deepest_call(str=str)
write(*,*) 'at bot of interface_call, str is "'//trim(str)//'"'
end subroutine interface_call
end module interface_call_m
program main
use interface_call_m, only : interface_call
implicit none
character(len=:), allocatable :: str
call interface_call(str=str)
write(*,*) 'at bot of main, str is "'//trim(str)//'"'
end program main
(Обратите внимание, что для простоты я не заключаю операторы записи в if(present)
и if(allocated)
, хотя это было бы необходимо для реальной реализации. )
В Intel 16.0 и 2019_U4, а также в PGI 15.10 эта процедура дает ожидаемый результат: str
устанавливается в deepest_call
и остается неизменным до interface_call
и main
:
$ ifort --version
ifort (IFORT) 16.0.0 20150815
Copyright (C) 1985-2015 Intel Corporation. All rights reserved.
$ ifort main.f90 && ./a.out
at bot of deepest_call, str is "12345"
at bot of interface_call, str is "12345"
at bot of main, str is "12345"
Однако с gfortran 4.8.5:
$ gfortran --version
GNU Fortran (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
Copyright (C) 2015 Free Software Foundation, Inc.
GNU Fortran comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of GNU Fortran
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING
$ gfortran main.f90 && ./a.out
at bot of deepest_call, str is "12345"
at bot of interface_call, str is ""
at bot of main, str is ""
Строка была обрезана при возврате из deepest_call
в interface_call
. В gfortran 7.3.0 и 8.2.0 код завершает работу во время выполнения, если не предоставлены параметры времени компиляции:
[chaud106@epyc-login-1-0 Testing]$ gfortran --version && gfortran main.f90 && ./a.out
GNU Fortran (GCC) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
at bot of deepest_call, str is "12345"
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x2af39a82733f in ???
#1 0x400c68 in ???
#2 0x400d9c in ???
#3 0x400f0e in ???
#4 0x2af39a813494 in ???
#5 0x400878 in ???
#6 0xffffffffffffffff in ???
Segmentation fault
Однако добавление проверки во время компиляции восстанавливает предыдущее поведение усечения:
$ gfortran --version
GNU Fortran (GCC) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gfortran -g -fbacktrace -Wall -Wextra -std=f2008 -fcheck=all -Og main.f90 && ./a.out
at bot of deepest_call, str is "12345"
at bot of interface_call, str is ""
at bot of main, str is ""
Для меня это очень похоже на ошибку компилятора, так что, возможно, мне просто нужно опубликовать сообщение на bugzilla. Но сначала я хотел бы получить некоторые отзывы, а именно:
Соответствует ли мой тестовый пример стандарту? Меня особенно интересует аргумент str=str
для deepest_call
. Я часто использую эту структуру, чтобы передать аргумент как необязательный, если и только если он необязателен в данной области, но я не мог легко найти это в стандарте, и я не уверен, действительно ли он действителен. Прохождение только str
, похоже, показало то же поведение.
Есть ли какие-нибудь простые обходные пути? Учитывая, что эта проблема затрагивает широкий спектр версий (4.8.5–8.2.0), просто избежать их невозможно.
Кто-нибудь знает об этом поведении для других версий gfortran, или другие компиляторы? У меня есть только легкий доступ к G CC, Intel и PGI.