Fortran ftell возвращается в неправильное положение

#fortran

#fortran

Вопрос:

Вот фрагмент простого кода, который считывает строку из файла, затем возвращается в предыдущую позицию и перечитывает ту же строку:

 program main
  implicit none
  integer         :: unit, pos, stat
  character(128)  :: buffer

  ! Open file as formatted stream
  open( NEWUNIT=unit, FILE="data.txt", ACCESS="stream", FORM="formatted", STATUS="old", ACTION="read", IOSTAT=stat )
  if ( stat /= 0 ) error stop

  ! Skip 2 lines
  read (unit,*) buffer
  read (unit,*) buffer

  ! Store position
  pos = ftell(unit)

  ! Read amp; write next line
  read (unit,*) buffer
  write (*,*) "buffer=", trim(buffer)

  ! Return to previous position
  call fseek(unit,pos,0)
  ! pos = ftell(unit)   ! <-- ?!

  ! Read amp; write next line (should be same output)
  read (unit,*) buffer
  write (*,*) "buffer=", trim(buffer)

  ! Close file stream
  close (UNIT=unit)

end program main
  

«data.txt » это просто фиктивный файл с 4 строками:

 1
2
3
4
  

Теперь, когда я компилирую фрагмент (gfortran 9.3.0) и запускаю его, я получаю ответ:

  buffer=3
 buffer=4
  

что неверно, поскольку они должны быть одинаковыми. Что еще интереснее, когда я добавляю дополнительную ftell (прокомментированную строку во фрагменте) после ‘fseek’, я получаю правильный ответ:

  buffer=3
 buffer=3
  

Есть идеи, почему он это делает? или я использую ftell и fseek неправильно?

Комментарии:

1. Обратите внимание, что ftell и fseek являются устаревшими нестандартными расширениями компилятора, которые не будут работать во всех компиляторах и не должны использоваться в новом коде. Если вы используете access="stream" , вы должны использовать inquire и read(unit,pos=) .

2. Второй @VladimirF, который опередил меня на секунду — посмотрите на запрос ( …. pos = … ) и напишите ( … pos = … ) для стандартного способа сделать это

Ответ №1:

в документации gfortran для FTELL и FSEEK четко указано, что эти процедуры предусмотрены для обратной совместимости с g77. Поскольку ваш код использует NEWUNIT , ERROR STOP , и STREAM access , вы не компилируете старый заплесневелый код. Вы должны использовать стандартные методы, соответствующие требованиям, как указано @Vladimir.

Быстрый сеанс отладки показывает это FTELL и FSEEK использует ссылку на 0 для позиции файла, в то время inquire как метод современного Fortran основан на 1. В gfortran может быть ошибка типа off-by-one, но, как FTELL и FSEEK для обратной совместимости с g77 (не поддерживаемый компилятор 15 летней давности), кому-то потребуется выполнить некоторую проверку кода, чтобы определить предполагаемое поведение. Я подозреваю, что ни один из нынешних активных разработчиков gfortran не заботится о том, чтобы изучить проблему. Итак, чтобы решить вашу проблему

 program main

  implicit none

  integer pos, stat, unit
  character(128) buffer

  ! Open file as formatted stream
  open(NEWUNIT=unit, FILE="data.txt", ACCESS="stream", FORM="formatted", amp;
  amp;  STATUS="old", ACTION="read", IOSTAT=stat)

  if (stat /= 0) stop

  ! Skip 2 lines
  read (unit,*) buffer
  read (unit,*) buffer

  ! Store position
  inquire(unit, pos=pos)

  ! Read amp; write next line
  read (unit,*) buffer
  write (*,*) "buffer=", trim(buffer)

  ! Reread amp; write line (should be same output)
  read (unit,*,pos=pos) buffer
  write (*,*) "buffer=", trim(buffer)

  ! Close file stream
  close (UNIT=unit)

end program main