我有一个C ++和Fortran 77的混合体,都是用G77编译的。
它主要是C ++,但它调用ODE求解器DVERK,然后回调到全局C函数以获得导数(用__stdcall
声明)。
它一切正常,直到我得到一个奇怪的SIGSEGV。
我追踪到了这一点,这是因为esp
正在减少其分段边界以下。
这样做的原因是DVERK包含**
运算符,它在内部是一个函数调用,具有两个由栈上的值传递的双精度值,为16个字节。
该函数返回答案,但后来我看到了这条指令:
sub 0x10,%esp
将堆栈指针递减16个字节,好像它将参数放回堆栈(?)
G77似乎在每次调用函数后执行此操作,并且通常它没有任何危害,因为堆栈指针未更改。
但是,在**
的情况下,堆栈指针保持递减,如果该代码执行了足够的次数,则递减直到我得到SIGSEGV。
(如果有足够的堆栈空间,则不会出现此问题,因为DVERK的返回会将其清除。)
我尝试用a**b
替换代码dexp(dlog(a)*b)
,但同样的事情发生了,除了它发生在两个步骤中,dlog
之后的8个字节和{{1}之后的8个字节}。
在设置G77与其运行时库使用的调用约定时,我必须做错。 专业知识赞赏。
答案 0 :(得分:2)
在这个时代,将C或C ++与Fortran混合的方法是使用ISO-C_Binding。从C ++开始,使用extern C调用。在Fortran中使用(英语单词)Fortran ISO C Binding用于调用的过程。这将导致Fortran使用C的调用约定(ABI)。然后您不必了解编译器内部。为此,您必须使用比g77更现代的Fortran编译器,例如gfortran。 gfortran完全能够编译FORTRAN 77.正式的ISO-C-Binding是Fortran 2003的一部分 - 你可以在C ++和现有的FORTRAN 77之间编写一个包装器。
有一个Stackoverflow标记解释了ISO-C-Binding:https://stackoverflow.com/tags/fortran-iso-c-binding/info