Fortran 77 处理 C++内存分配
我正在尝试编写一个使用几万行 Fortran 77 代码的 C++ 程序,但遇到了一些奇怪的错误。我将三个坐标 (x,y,z) 和三个向量的地址从 C++ 传递到 fortran 中,然后让 fortran 对初始点运行一些计算并返回三个向量中的结果。
我在 C++ 函数中执行了数百次,然后离开该函数,然后再回来执行此操作。第一次它工作得很好,但第二次它停止返回具有正 x 分量的点的有用结果(返回 nan)。
最初,它看起来像是一个算法问题,除了三件事:
- 它在我运行它的前 200 次中完美地工作
- 如果我从 fortran 调用它并完全消除 C++ 它就可以工作(对于最终程序不可行)
- 我尝试添加 print 语句到 fortran 来调试出错的地方,但事实证明,如果我将打印语句添加到特定的子例程(甚至像 PRINT *,'Here' 这样简单的东西),程序即使在第一次运行时也会开始返回 NaN。
这就是为什么我认为这与 C 和 Fortran 函数/子例程调用之间的内存分配和释放方式有关。基本设置如下所示: C++: <代码>
void GetPoints(void);
外部“C”
{
void getfield_(float*,float*,float*,float[],float[],float[],int*,int*);
}
int main(无效)
{
获取点(); //作品
获取点(); //没有
}
无效 GetPoints(无效)
{
浮动 x、y、z;
整数 i,n,l;
l=50;
n=1;
x=y=z=0.0;
浮点数 xx[l],yy[l],zz[l]
for(i=0;i<
l;i++)
getfield_(&x,&y,&z,xx,yy,zz,&n,&l);
//将当前的xx,yy,zz存储在大全局数组中
}
福特兰语言: <代码>
SUBROUTINE GETFIELD(XI,YI,ZI,XX,YY,ZZ,IIN,NP)
DIMENSION XX(NP),YY(NP),ZZ(NP)
EXTERNAL T89c
T89c(XI,YI,ZI,XX,YY,ZZ)
RETURN
END
!In T89c.f
SUBROUTINE T89c(XI,YI,ZI,XX,YY,ZZ)
COMMON /STUFF/ ARRAY(100)
!Lots of calculations
!Calling ~20 other subroutines
RETURN
END
你们中有人看到我造成的任何明显的内存问题吗?也许 Fortran 认为存在但实际上被 C++ 释放的常见块?由于无法使用 print 语句进行调试,也没有时间尝试理解别人的几千行 Fortran 77 代码,我愿意尝试你们所有人建议或想到的任何内容。
我使用 g++ 4.5.1 来编译 C++ 代码和最终链接,使用 gfortran 4.5.1 来编译 fortran 代码。
谢谢
**编辑:**
我已经将错误追溯到我出生之前编写的一些晦涩的代码片段。看起来它正在寻找一些多年来在更新中被删除的常见变量。我不知道为什么它只影响一维,也不知道为什么可以通过添加打印语句来复制该错误,但我仍然消除了它。谢谢大家的帮助。
I'm trying to write a C++ program that utilizes a few tens of thousands of lines of Fortran 77 code, but running into some strange errors. I'm passing three coordinates (x,y,z) and the address of three vectors from C++ into fortran, then having fortran run some computations on the initial points and return results in the three vectors.
I do this a few hundred times in a C++ function, leave that function, and then come back to do it again. It works perfectly the first time through, but the second time through it stops returning useful results (returns nan) for points with a positive x component.
Initially it seems like an algorithm problem, except for three things:
- It works perfectly the first 200 times I run it
- It works if I call it from fortran and eliminate C++ altogether (not viable for the final program)
- I've tried adding print statements to fortran to debug where it goes wrong, but turns out if I add print statments to a specific subroutine (even something as simple as PRINT *,'Here'), the program starts returning NaNs even on the first run.
This is why I think it's something to do with how memory is being allocated and deallocated between C and fortran function/subroutine calls. The basic setup looks like this:
C++:
void GetPoints(void);extern"C" { void getfield_(float*,float*,float*,float[],float[],float[],int*,int*); }
int main(void) { GetPoints(); //Works GetPoints(); //Doesn't }
void GetPoints(void) { float x,y,z; int i,n,l; l=50; n=1; x=y=z=0.0; float xx[l],yy[l],zz[l] for(i=0;i
<
l;i++) getfield_(&x,&y,&z,xx,yy,zz,&n,&l); //Store current xx,yy,zz in large global array }
Fortran:
SUBROUTINE GETFIELD(XI,YI,ZI,XX,YY,ZZ,IIN,NP) DIMENSION XX(NP),YY(NP),ZZ(NP) EXTERNAL T89c T89c(XI,YI,ZI,XX,YY,ZZ) RETURN END
!In T89c.f SUBROUTINE T89c(XI,YI,ZI,XX,YY,ZZ) COMMON /STUFF/ ARRAY(100) !Lots of calculations !Calling ~20 other subroutines RETURN END
Do any of you see any glaring memory issues that I'm creating? Perhaps common blocks that fortran thinks exist but are really deallocated by C++? Without the ability to debug using print statements, nor the time to try to understand the few thousand lines of someone else's Fortran 77 code, I'm open to trying just about anything you all can suggest or think of.
I'm using g++ 4.5.1 for compiling the C++ code and final linking, and gfortran 4.5.1 for compiling the fortran code.
Thanks
**Edit:**
I've tracked the error down to some obscure piece of the code that was written before I was even born. It appears it's looking for some common variable that got removed in the updates over the years. I don't know why it only affected one dimension, nor why the bug was replicatable by adding a print statement, but I've eliminated it nonetheless. Thank you all for the help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可能会遇到“差一”错误。 Fortran 数组是从 1 开始的,而 C 数组是从 0 开始的。确保传入 Fortran 的数组大小不比应有的大小小 1。
编辑:
我想它看起来是对的...不过,我会尝试在 C++ 函数中分配 51 个元素,只是为了看看会发生什么。
顺便说一下
float xx[l];
不是标准的。这是海湾合作委员会的一项功能。通常,您应该在此处使用new
分配内存,或者您应该使用std::vector
。另外,我对循环中对 getfield_ 的调用感到困惑。您不应该将
i
传递给getfield_
吗?You may be running into the "off-by-one" error. Fortran arrays are 1-based, while C arrays are 0-based. Make sure the array sizes you pass into Fortran are not 1 less than they should be.
Edit:
I guess it looks right... Still, I would try allocating 51 elements in the C++ function, just to see what happens.
By the way
float xx[l];
is not standard. This is a gcc feature. Normally you should be allocating memory withnew
here, or you should be usingstd::vector
.Also, I am confused by the call to
getfield_
in the loop. Shouldn't you be passingi
togetfield_
?您还应该在子例程
T89c
中将XX
、YY
和ZZ
声明为数组,如下所示:C/C++ 应该一般来说,永远不要释放任何 Fortran 公共块。它们就像 C 中的
struct
(即内存在编译时保留,而不是在运行时保留)。由于某种原因,即使没有上述声明,gfortran 似乎也接受 T89c 中的以下内容:
在编译期间,但在执行时出现分段错误。
You should declare
XX
,YY
andZZ
as arrays also in the subroutineT89c
as follows:C/C++ should in general never deallocate any Fortran common blocks. These are like
structs
in C (i.e. memory is reserved at compile time, not at runtime).For some reason, gfortran seems to accept the following in
T89c
even without the above declarations:during compilation but when executing it I get a segmentation fault.