我正在开发一个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 中 main 函数的 dirpwf
指针获取正确的值,FileNameSize
变量中存储的字符串大小也是正确,而 Fortran 认为接收到的大小(显然是 -136420716)小于预期 (80)。
我该如何解决这个问题?
最佳答案
Fortran 和 C 以不同的方式记录字符串长度。 C 在末尾使用 NUL 字符作为终止符,而 Fortran 则单独保留长度。 Fortran 如何做到这一点取决于实现。对于调用 Fortran 过程,大多数编译器都会查找作为指定参数后面的附加参数传递的长度,作为按值传递的地址大小的整数。但这不是通用的,也不是可移植的。您已经传递了这些长度,但在字符串地址之后立即这样做了 - 这不是 gfortran 想要的地方。
Fortran 2003 引入了 C 互操作性功能,允许您以可移植的方式混合使用 Fortran 和 C。 Fortran 2008 在某种程度上扩展了这一点,而 Fortran 2018 则进一步扩展了它。不幸的是,即使在 F2018 中,将字符串从 C 传递到 Fortran 仍然很困惑。
人们可能认为简单的解决方案是将 BIND(C)
添加到 Fortran 子例程 header - 这告诉 Fortran 不要使用隐藏参数等。但是不允许您使用 CHARACTER*80 等。
最简单的修复方法是将 n、m、l 和 h 移动到 C 调用中参数列表的末尾,删除大小的 Fortran 参数,并将 n、m、l 和 h 设置为 size_t 而不是 int。另外,不要使用 & 来传递它们。这仍然是不可移植的,但它现在可以帮助您继续前进。
关于c - 将字符串参数从 C 传递到 Fortran 子例程时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48465274/