使用文件重定向或管道提供命令并不总是有效

使用文件重定向或管道提供命令并不总是有效

我已经下载了这个程序构造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.p3dnaca0012.nmf)。

当我手动运行并一一construct2d键入选项时,它按预期工作。instructions.txt我尝试使用gdb它来调试它,但不幸的是它没有显示任何特别的东西。

因此,程序在从文件提供指令时似乎忽略了一些指令。为什么会发生这种情况?

  • 程序按预期运行时的 stdout 输出(此外,程序将生成输出文件:naca0012.p3dnaca0012.nmf):工作日志

  • 当程序未按预期运行时的标准输出(没有输出文件):不工作日志

我非常感谢你的帮助。

编辑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 的回答解释了这种情况首先发生的原因。

相关内容