Фортран читает ошибку сегментации SIGSEGV - PullRequest
0 голосов
/ 08 мая 2020

Я не знаком с Фортраном, но мне пришлось использовать старый код моего советника, но он не работал, и я мог отследить его до минимального рабочего примера.

hello.f следует :

  implicit none
  character*200 rec
  integer var,idum
  real*4 rdum
  call xparse('-t0',1,1,'required',rec,idum,rdum)
  print *, rec
  read(rec,'(i6)')   var
  print *, var
  END

И extra.f выглядит следующим образом:

c------------------------------------------------------------------
      subroutine xparse(cc,nth,ifo,req,carg,iarg,rarg)
c------------------------------------------------------------------
      character*(*) cc,req,carg
      character*256 rec
c
      iver=0
      lcc=len(cc)
      na=iargc()
      ith=0
      do 100 ia=1,na
      call getarg(ia,rec)
      if(rec(1:15).eq.'-xparse_verbose') iver=1
      lrec=ilen(rec,256)
      if(lrec.eq.lcc) then
      if(rec(1:lcc).eq.cc(1:lcc)) then
      if(iver.eq.1)write(0,'(a,a)')'xparse ,parsing:',rec(1:lcc)
c
      if(nth.le.0) then
      iarg=1
      return
      endif
c
      ith=ith+1
      if(ith.eq.nth) then
c
      if(ia.eq.na) then
      write(0,*)'parse error :  missing value for ',cc
      endif
      call getarg(ia+1,rec)
      lrec=ilen(rec,256)
      if(iver.eq.1)write(0,'(a,a)')'xparse, string:',rec(1:lrec)
      if(ifo.eq.1) then
      if(iver.eq.1)write(0,'(a,a)')'xparse, character:',rec(1:lrec)
      carg=rec
      else if(ifo.eq.2) then
      s=gets(rec)
      if(s.ge.0.0)iarg=s+0.1
      if(s.lt.0.0)iarg=s-0.1
      if(iver.eq.1)write(0,*)'xparse, integer:',iarg
      else if(ifo.eq.3) then
      rarg=gets(rec)
      if(iver.eq.1)write(0,*)'xparse, real:',rarg
      endif
      return
c
      endif
      endif
      endif
100   continue
c
      if(req(1:8).eq.'required') then
      write(0,*)'parse error :  cant find required arg:  ',cc
      stop
      endif
      end
c------------------------------------------
      real function gets(cc)
c------------------------------------------
c
c  decodes integer or floating f format
c  from character string
c
      character*(*) cc
      nn=len(cc)
c
      gets=0.0
      fak=1.
      ief=0
      l1=0
      l2=0
      do 200 i=1,nn
      if(cc(i:i).eq.'e'.or.cc(i:i).eq.'E')ief=i
      if(cc(i:i).eq.'d'.or.cc(i:i).eq.'D')ief=i
      if(l1.eq.0.and.cc(i:i).ne.' ')l1=i
      if(cc(i:i).ne.' ')l2=i
      if(cc(i:i).eq.' '.and.l2.gt.0) goto 201
200   continue
201   continue
      nn=l2
      if(ief.gt.0) then
      lex=l2-ief
      iex=-9999999
      if(lex.eq.1)read(cc(ief+1:l2),'(i1)',err=900) iex
      if(lex.eq.2)read(cc(ief+1:l2),'(i2)',err=900) iex
      if(lex.eq.3)read(cc(ief+1:l2),'(i3)',err=900) iex
      if(lex.eq.4)read(cc(ief+1:l2),'(i4)',err=900) iex
      if(lex.eq.5)read(cc(ief+1:l2),'(i5)',err=900) iex
      if(iex.gt.-999999) then
      if(iex.lt.0)fak=1./( 10.**(-iex) )
      if(iex.gt.0)fak=10.**iex
      else
      write(0,*)'gets: cannot read ',cc
      endif
      nn=ief-1
      endif
c
      sig=1.
      ss=0.
      tt=1.
      ip=0
      do 100 l=1,nn
      if(cc(l:l).ne.' ') then
      if(cc(l:l).eq.'.') then
      ip=1
      else if(cc(l:l).eq.'-') then
      sig=-1.
      else
c      read(cc(l:l),'(i1)',err=900) ii
      ii=ichar(cc(l:l))-48
      if(ii.lt.0.or.ii.gt.9) goto 109
      if(ip.eq.0) then
      ss=10.*ss+float(ii)
      else
      tt=0.1*tt
      ss=ss+tt*float(ii)
      endif
      endif
      endif
100   continue
109   continue
      gets=ss*sig*fak
      return
900   continue
      write(0,*)' gets: error reading formatted integer:'
      write(0,*)nn
      write(0,'(a,a,a)')'$',cc,'$'
      return
      end
c-------------------------------------
      integer function ilen(c,m)
c-------------------------------------
      character*80 c
      k=1
      do 100 i=1,m
      if(c(i:i).ne.' '.and.c(i:i).ne.char(0))k=i
100   continue
      ilen=k
      jlen=k
      return
      end

Если я это сделаю

gfortran hello.f extra.f

./a.out -t0 10800

Я получаю сообщение об ошибке

10800

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Backtrace for this error:
#0  0x10a01735c
#1  0x10a0166f3
#2  0x7fff7376cb5c
#3  0x10a15b340
#4  0x10a15bd2d
#5  0x10a15978f
#6  0x10a00c917
#7  0x10a00c9e5
Segmentation fault: 11

Эта функция чтения (?) Часто используется в коде для чтения введенных пользователем данных (например, sys.argv Python), но я не понимаю, почему она не работает.

Я использую GNU Fortran (Homebrew G CC 9.3.0_1) 9.3.0, MacOS Mojave 10.14.6.

1 Ответ

0 голосов
/ 08 мая 2020

Ошибка в функции ilen. Рассмотрим

      character*80 c
      k=1
      do 100 i=1,m
      if(c(i:i).ne.' '.and.c(i:i).ne.char(0))k=i
100   continue

Переменная (фиктивный аргумент) c объявлена ​​как имеющая длину 80, но в l oop подстрока c(81:81) обязательно будет доступна, если m - больше, чем 80 (что и происходит при вызове в программе). Это неверно.

Вы можете проиндексировать c до позиции 80 с помощью

      do 100 i=1,80
      ...

или до его длины:

      do 100 i=1,len(c)
      ...

В качестве альтернативы вы можете сделать c иметь длину 256 или необязательно (обязательно) 80:

c Have the length of the dummy argument assumed
      character*(*) c

или

c Have the length given by the argument m
      character*(m) c

Существуют также современные способы написания объявлений символов, например

      character(len=*) c

и

      character(len=m) c
...