Передача строки в строку вызова подпрограммы, где параметр имеет определенную длину, дает неожиданные результаты - PullRequest
4 голосов
/ 17 января 2012

Я обнаружил, что этот код ведет себя неожиданно

module testmodule
   integer, parameter :: LCHARS = 50
contains
   subroutine init()
      call foobar("foobar")
   end subroutine

   subroutine foobar(s)
      character(len=*), intent(in) :: s
      call bar(s)
   end subroutine

   subroutine bar(str)
      character(len=LCHARS), intent(in)  :: str

      print *, str
   end subroutine
end module

program foo
   use testmodule
   call init()
end program

Этот код печатает мусор, зависящий от компилятора.

Я вижу проблему в том, что я прыгаю через процедуру с len=* для строкового аргумента, который затем передается подпрограмме с заданной длиной для строкового аргумента.

Что происходит именно под капотом и где в стандарте описывается это поведение?Стоит ли воздерживаться от указания длины для аргументов символьной процедуры, поскольку такое поведение может произойти в любое время без предупреждения?

Ответы [ 3 ]

5 голосов
/ 17 января 2012

Я думаю, что ваш код не соответствует. Раздел 12.4.1.1 стандарта Fortran 95 гласит:

12.4.1.1 Фактические аргументы, связанные с фиктивными объектами данных
[...]
Если скалярный фиктивный аргумент имеет тип символа по умолчанию, длина фиктивного аргумента len должно быть меньше или равно длине фактического аргумента. Пустой аргумент становится связанный с крайними левыми len символами фактического аргумента.

3 голосов
/ 17 января 2012

Проблема в том, что bar требуется строка длиной 50 (ср. character(len=LCHARS), intent(in) :: str), тогда как передаваемая строка имеет длину только 6. Компиляция с помощью

ifort-Warn all, nodec, интерфейсы, объявления -gen_interfaces -check all -std test.f90

выдает ошибку

forrtl: тяжелый (408): форт: (18): фиктивная символьная переменная 'STR' имеет длину 50, которая больше, чем фактическая длина переменной 6

Насколько известно , все аргументы Фортрана передаются по ссылке .За кулисами функция bar получает указатель на начало строки str и дополнительный параметр, значение которого равно длине строки.Таким образом, bar займет 50 символов памяти, начиная с начала str, и выведет его на экран.Поскольку передаваемая строка имеет длину всего 6 символов, оставшиеся 44 символа будут такими, какие будут в следующем бите памяти после «foobar», который будет отличаться во время выполнения или в зависимости от используемого компилятора.

2 голосов
/ 17 января 2012

Передача аргумента зависит от компилятора, если выполняются требования стандарта, но обычно фиктивный аргумент CHARACTER (len = *) будет иметь интерфейс, похожий на

void foo (char * s, int len)

и в реализации процедуры foo в качестве длины строки используется скрытый аргумент len. OTOH, для аргумента CHARACTER (len = somevalue) скрытый аргумент len либо игнорируется, либо вообще не передается, а код процедуры предполагает, что somevalue является правильной длиной строки.

Как вы уже видели, вы никогда не должны использовать ничего, кроме LEN = *, если вы действительно не знаете, что делаете, и не можете процитировать главу и стих из стандарта, чтобы объяснить, почему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...