![使用文件重定向或管道提供命令并不总是有效](https://linux22.com/image/180198/%E4%BD%BF%E7%94%A8%E6%96%87%E4%BB%B6%E9%87%8D%E5%AE%9A%E5%90%91%E6%88%96%E7%AE%A1%E9%81%93%E6%8F%90%E4%BE%9B%E5%91%BD%E4%BB%A4%E5%B9%B6%E4%B8%8D%E6%80%BB%E6%98%AF%E6%9C%89%E6%95%88.png)
我已经下载了这个程序构造2d并使用 GNU Fortran 编译它gfortran 9.3.0
。您可以使用 gnu make 编译该程序:
make
(编译时间:在运行带有 GNU bash 的 Ubuntu 20.04 版本 5.0.17(1)-release (x86_64-pc-linux-gnu) 的 PC 上需要 10 秒)。
该程序不适用于参数,而是我必须手动输入选项。为了避免繁琐的工作流程,我将选项写入文件中instructions.txt
以供其使用。
construct2d < instructions.txt
其内容instructions.txt
为:
naca0012.dat
SOPT
NSRF
80
RADI
5
NWKE
5
QUIT
VOPT
JMAX
5
YPLS
5
RECD
1E5
QUIT
GRID
SMTH
QUIT
该文件naca0012.dat
可以在未压缩的 Construction2D 存档的目录下找到sample_airfoils
,也可以从此下载关联。
问题是该命令:
construct2d < instructions.txt
当我只运行一次时没有给出预期结果,我必须运行上面的命令几次(可能是 4 次)才能获得预期结果:(预期输出是:naca0012.p3d
和naca0012.nmf
)。
当我手动运行并一一construct2d
键入选项时,它按预期工作。instructions.txt
我尝试使用gdb
它来调试它,但不幸的是它没有显示任何特别的东西。
因此,程序在从文件提供指令时似乎忽略了一些指令。为什么会发生这种情况?
我非常感谢你的帮助。
编辑1:
在 Windows 10 上,使用 gfortran 8.1.0,文件重定向工作得很好,不会失败。正如我上面所描述的,这种情况只发生在 Linux 上。
编辑2:我确认这与行结尾无关。因为我已经在 Linux 上创建了该文件instructions.txt
本身。并使用dos2unix
工具检查文件。
编辑3 我尝试使用旧版本的 gfortran(Ubuntu 服务器 18.04 上的 gfortran 7.5.0)编译该程序,一切正常。这可能是较新版本的 GNU Fortran 中的一个错误。
编辑4:
我通过添加标志-Og
或-O0
编译程序时解决了 gfortran 9.x 和 10.x 中的奇怪行为。
答案1
来自 comp.lang.fortran 的贡献者:
一个问题似乎是主循环的位置:
done = .false.
do while (.not. done)
call main_menu(command)
call run_command(command, surf, options, done, ioerror)
end do
调用“run_command”:
subroutine run_command(command, surf, options, done, ioerror)
...
logical, intent(out) :: done
integer, intent(inout) :: ioerror
gfortran 似乎猜测,由于“run_command”从未使用“done”的值,因此实际执行语句“done = .false”是没有意义的。并且由于“run_command”实际上不会将其参数“done”设置为任何内容,除非它看到“quit”命令,因此当主循环检查“done”时,“done”将保持未初始化状态。有时它是假的,有时它包含垃圾,在这种情况下它被评估为真并且主循环提前终止。
将“done”的意图更改为“inout”似乎可以解决问题。
在 run_command 中的“select case”语句之前设置“done”似乎也有效:
done = .false.
select case (command)
...
我的猜测是,这是解决此问题的正确方法,并且编译器的行为虽然令我们中的一些人(包括我)感到惊讶,但实际上是正确的。
valgrind 帮助找到了这个。
还有另一张海报:
同样,以下几个实例
type(options_type), intent(out) :: opt
在文件 menu.f90 中应更改为
type(options_type), intent(inout) :: opt
或者应该省略intent子句,因为当进入子程序时,带有intent(out)的参数将变得未定义,并且除非它在返回之前获取子程序中的值,否则将保持未定义状态。
其他建议包括使用检查数组边界的选项进行编译和运行等。
答案2
我尝试使用旧版本的 gfortran(gfortran 7.x 和 8.x)编译该程序,一切正常。但较新版本的 gfortran(9.x 和 10.x)仍然存在该问题。但是,我通过添加标志-Og
或-O0
编译程序时解决了 gfortran 9.x 和 10.x 中的奇怪行为。
@RoboNerd 的回答解释了这种情况首先发生的原因。