将主程序内部函数作为参数传递时触发Segmentation fault问题
搞定WSL Ubuntu 16里Fortran内部函数传参的段错误问题
嘿,我碰到过类似的WSL兼容性问题,来给你拆解一下:
先把你的问题理清楚
你说在WSL Ubuntu 16环境里,把主程序的内部函数当参数传给另一个子程序,调用这个函数时就触发Segmentation fault,但原生Linux或者Mac上跑完全没问题。我帮你补全了可复现的完整代码版本:
module test1 implicit none contains subroutine x(ff,y) interface real function ff(y) real, intent(in) :: y end function ff end interface real, intent(in) :: y print *, ff(y) ! 就是这行触发段错误 end subroutine x end module test1 program main use test1 implicit none call x(my_func, 3.0) contains real function my_func(y) real, intent(in) :: y my_func = y * 2.0 end function my_func end program main
为啥只有WSL 1会出问题?
你用的Ubuntu 16搭配的应该是WSL 1,它是通过翻译层模拟Linux系统调用的,和原生Linux的ABI(应用二进制接口)存在细微差异。再加上Ubuntu 16默认的GCC版本是5.x,这个版本的Fortran编译器在WSL 1环境下,处理内部函数作为过程参数传递时,没有正确保留内部函数依赖的主程序栈帧上下文,导致调用时访问了无效内存,直接崩了。
而原生Linux或Mac要么用了更新的GCC版本,要么系统本身的兼容性更好,所以没这个坑。
几个可行的解决办法
1. 升级到WSL 2(最推荐)
WSL 2用的是真正的Linux内核,和原生Linux几乎没差别,能从根源上解决这类兼容性问题。升级步骤很简单:
# 先查看当前WSL版本 wsl --list --verbose # 把Ubuntu 16升级到WSL 2(记得先备份重要数据) wsl --set-version Ubuntu-16.04 2
2. 升级GCC编译器
Ubuntu 16默认的GCC太老了,换个新点的版本(比如GCC 7)就能修复这个bug:
# 添加工具链PPA sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update # 安装GCC 7和对应的Fortran编译器 sudo apt install gcc-7 gfortran-7 # 设置gfortran默认用7版本 sudo update-alternatives --install /usr/bin/gfortran gfortran /usr/bin/gfortran-7 100
3. 重构代码,避开内部函数传参
如果暂时没法升级环境,那就把内部函数移到模块里,变成模块函数——这样传递的时候就不需要依赖主程序的栈帧了,自然不会崩:
module test1 implicit none contains subroutine x(ff,y) interface real function ff(y) real, intent(in) :: y end function ff end interface real, intent(in) :: y print *, ff(y) end subroutine x ! 把原来的内部函数移到模块里 real function my_func(y) real, intent(in) :: y my_func = y * 2.0 end function my_func end module test1 program main use test1 implicit none call x(my_func, 3.0) end program main
验证一下
不管用哪种方法,改完之后重新编译运行:
gfortran your_code.f90 -o test_run ./test_run
如果输出6.0000000,说明问题已经解决啦!
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

