fortran - Fortran 读取 SIGSEGV 分段错误
问题描述
我对 Fortran 不熟悉,但我不得不使用我顾问的旧代码,但它不起作用,我可以将它追踪到一个最小的工作示例。
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
该读取函数(?)是代码中经常用于读取用户输入的函数(如 Python 的 sys.argv),但我不明白它为什么会失败。
我正在使用 GNU Fortran (Homebrew GCC 9.3.0_1) 9.3.0,MacOS Mojave 10.14.6。
解决方案
函数中存在错误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,但在循环中,如果子字符串大于(在程序中调用时),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
推荐阅读
- swift - 在 Swift 5 中调用函数导致错误“表达式类型不明确,没有更多上下文”
- microsoft-graph-api - 为什么我可以订阅频道中的所有消息,但不能订阅用户的所有消息?
- docker - 无法通过 Chocolatey 卸载 Docker Desktop
- windows - Windows 注册表命令文件夹中的 --url -- 是什么意思?
- css - 如何显示行/行以使用 CSS 链接 2 个或更多元素?
- node.js - NodeJS 在没有 Express 的情况下获取 cookie
- sql - foreach 循环遍历 SQL 数据数组时出现 Powershell IComparable 错误
- ios - AzureIoTHubClient 包装器框架无法构建模块
- tensorflow2.0 - 给定一个输入并得到两个输出
- merge - Apache NiFi:MergeContent 无法正确合并文件