我正在开发一个Linux程序,它通过命令行接收一些用户参数。
用户界面是用C语言编写的,数据处理是在Fortran中,因此C语言中的主要功能将一些参数传递给Fortran子程序。其中一些参数是字符串,我们遇到了问题。 以下是代码的一些部分:
C主要功能:
extern void anaconv_(char *FileName,int *n,char *PlanName,int *m,char *TipoDados,char *FrontName,int *l,char *Dirdat, int *h, bool *kvuge, bool *ch_serie, bool *ch_shuntb, bool *simulacao);
void ajuda_anaconv(void);
int main (int argc, char **argv)
{
int i;
int n,m,l,h;
bool flagk = 0;
bool flags = 0;
bool flagp = 0;
bool flagsimul = 0;
char *dirpwf = malloc(sizeof(char)*80);
char *dirbar = malloc(sizeof(char)*80);
char *dirfro = malloc(sizeof(char)*80);
char *dirdat = malloc(sizeof(char)*500);
char *tpdados = malloc(sizeof(char));
...
dirpwf = argv[i+1];
i++;
...
dirbar = argv[i+1];
i++;
...
dirfro = argv[i+1];
i++;
...
dirdat = argv[i+1];
i++;
...
tpdados = argv[i+1];
i++;
...
n = strlen(dirpwf)
m = strlen(dirbar)
l = strlen(dirfro)
h = strlen(dirdat)
...
anaconv_(dirpwf,&n,dirbar,&m,tpdados,dirfro,&l,dirdat,&h,&flagk,&flags,&flagp,&flagsimul);
...
free(dirpwf);
free(dirbar);
free(dirfro);
free(dirdat);
free(dirdatcomp);
free(tpdados);
...
return 1;
}
他们,Fortran子程序就像:
SUBROUTINE ANACONV
+(FileName,FileNameSize,PlanName,PlanNameSize,TpData,FrontName,FrontNameSize,Dirdat,DirdatSize,kVUGE,CHSERIE,CHSHUNTB,SIMUL)
IMPLICIT NONE
CHARACTER*80 FileName,PlanName,FrontName
CHARACTER*500 Dirdat
INTEGER*4 FileNameSize,PlanNameSize,FrontNameSize,DirdatSize
CHARACTER*1 TpData
LOGICAL*1 kVUGE,CHSERIE,CHSHUNTB,SIMUL
...
END SUBROUTINE ANACONV
编译器是gcc版本4.8.5 20150623,我在CentOS Linux版本7.3.1611中运行该程序。
虽然代码编译没有问题,但是当我运行程序传递一些参数时,我收到以下消息:
Fortran runtime error: Actual string length is shorter than the declared one for dummy argument 'filename' (-136420716/80)
我试图找到用gdb调试的问题,但是我找不到错误。 FileName
字符串从C中主函数的dirpwf
指针获取正确的值,并且FileNameSize
变量中存储的字符串大小也正确,而Fortran知道接收的大小(显然-136420716)低于预期(80)。
我该如何解决这个问题?
答案 0 :(得分:2)
Fortran和C以不同方式跟踪字符串长度。 C在末尾使用NUL字符作为终结符,而Fortran则分别保持长度。 Fortran如何做到这一点取决于实现。对于调用Fortran过程,大多数编译器会查找在命名过程之后作为附加参数传递的长度,作为按值传递的地址大小的整数。但这不是普遍的,也不是便携式的。你已经通过了这些长度,但是在字符串地址之后立即这样做了 - 这不是gfortran想要的地方。
Fortran 2003引入了C互操作性功能,允许您以可移植的方式混合使用Fortran和C. Fortran 2008有所扩展,Fortran 2018扩展了它。不幸的是,即使在F2018中,将字符串从C传递到Fortran仍然很混乱。
有人可能会认为简单的解决方案是将BIND(C)
添加到Fortran子例程标头中 - 这会告诉Fortran不要使用隐藏的参数等。但是,不允许使用CHARACTER * 80等。
最简单的解决方法是将n,m,l和h移动到C调用中参数列表的末尾,删除大小的Fortran参数,并使n,m,l和h size_t而不是int。另外,不要使用&通过他们。这仍然是不可携带的,但它现在可以帮助您。