我有一个带有例程的 FORTRAN 代码:
SUBROUTINE READ_NC_VALS(NCID, RECID, VARNAME, VARDATA)
integer ncid, recid
character*(*) varname
real*8 vardata
dimension vardata(15,45,75)
etc.
Run Code Online (Sandbox Code Playgroud)
我想为这段代码添加一些灵活性,我想我会通过首先添加一个可选的标志参数来实现:
SUBROUTINE READ_NC_VALS(NCID, RECID, VARNAME, VARDATA, how_to_calculate)
! everything the same and then ...
logical, optional :: how_to_calculate
Run Code Online (Sandbox Code Playgroud)
现在,我什至没有使用“how_to_calculate”。我只是将其放入代码中进行测试。所以我顺利地编译了代码。然后我运行它,在子例程中出现错误。具体来说,稍后代码中的某些值会“神奇地”改变为没有该可选参数的值。新值对代码逻辑没有意义,因此它会礼貌地退出并显示错误消息。让我再次强调,此时我什至没有使用这个可选参数。然后,我高兴地回到源代码中调用此例程的所有位置,即使我的新参数是可选的,我也会在所有调用中为其添加值。当我这样做时,代码运行良好。那么这是什么一回事?子例程中仅存在未使用的可选参数如何会导致其他数据被损坏?为这个可选参数添加输入参数如何再次解决问题?顺便说一句,这是用 PGI 编译的。
有任何想法吗?谢谢。
顺便说一句,很抱歉没有提供更多代码。如果我这样做的话,我的老板可能会对我不太满意。规则不是我制定的;我只是在这里工作。
Fortran 中的可选参数是通过0
为调用子例程没有提供值的每个可选参数传递(空指针)来实现的。由于这个带有可选参数的子例程必须:
INTERFACE
要么在调用子例程中有显式定义如果向子例程添加可选参数,但它在调用方中既没有接口也不是模块级子例程,则编译器将不会生成正确的调用序列 - 它将传递比预期更少的参数。这可能会在 Unix 系统上造成问题,其中 PGICHARACTER*(*)
在参数列表末尾传递所有参数的长度(在 Windows 上,它将长度作为字符串地址之后的下一个参数传递)。缺少一个参数会改变堆栈中长度参数的位置(或者将它们放入 x64 上的错误寄存器中),从而导致VARNAME
接收到的字符串长度不正确READ_NC_VALS
。这可能会导致各种不良行为,包括覆盖内存和“神奇地”改变不应该根据程序逻辑改变的值。