我正在尝试编写一个使用数万行Fortran 77代码的C程序,但遇到了一些奇怪的错误 . 我将三个坐标(x,y,z)和三个向量的地址从C传递到fortran,然后让fortran对初始点运行一些计算并将结果返回到三个向量中 .
我在C函数中这样做几百次,保留该函数,然后再回来再做一次 . 它第一次完美地工作,但第二次通过它停止返回具有正x分量的点的有用结果(返回nan) .
最初它似乎是一个算法问题,除了三件事:
-
我运行前200次完美运行
-
如果我从fortran调用它并且完全消除C(对于最终程序不可行)它是有效的
-
我'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 *,'这里'),程序即使在第一次运行时也开始返回NaNs .
这就是为什么我认为它与如何在C和fortran函数/子例程调用之间分配和释放内存有关 . 基本设置如下所示: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
你们有没有看到我正在创造的任何明显的记忆问题?也许Fortran认为存在的常见块,但是真的被C解除了?如果没有使用print语句进行调试的能力,也没有时间尝试理解其他人的Fortran 77代码的几千行,我愿意尝试任何你可以建议或想到的东西 .
我使用g 4.5.1编译C代码和最终链接,并使用gfortran 4.5.1编译fortran代码 .
谢谢
编辑:
我已经将错误跟踪到我出生之前编写的代码中一些不起眼的部分 . 看起来它正在寻找多年来在更新中删除的一些常见变量 . 我不知道为什么它只影响一个维度,也不知道为什么bug可以通过添加print语句来复制,但我已经将其删除了 . 谢谢大家的帮助 .
2 回答
您可能遇到了“off-by-one”错误 . Fortran阵列基于1,而C阵列基于0 . 确保传递给Fortran的数组大小不比它们少1 .
编辑:
我想它看起来是正确的......但是,我会尝试在C函数中分配51个元素,只是为了看看会发生什么 .
顺便说一下
float xx[l];
不是标准的 . 这是一个gcc功能 . 通常你应该在这里用new
分配内存,或者你应该使用std::vector
.另外,我对循环中对
getfield_
的调用感到困惑 . 你不应该将i
传递给getfield_
吗?您应该在子例程
T89c
中将XX
,YY
和ZZ
声明为数组,如下所示:通常,C / C应该永远不会释放任何Fortran公共块 . 它们类似于C中的
structs
(即内存在编译时保留,而不是在运行时保留) .出于某种原因,即使没有上述声明,gfortran似乎也接受了_1668013中的以下内容:
在编译期间但在执行时我遇到了分段错误 .