c - 将字符串参数从 C 传递到 Fortran 子例程时出现问题

标签 c linux string fortran

我正在开发一个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/

相关文章:

c - struct sockaddr_un 与 sockaddr

linux - 在PiTooth.py程序中从第二个终端配对后,另一个终端中的程序仍然是 "waiting for connection"

java - 根据某些规则替换 EditText 中的字母

c - 与gcc中的共享库链接时如何为可执行文件生成位置相关代码?

c - 测量从模拟输入到阵列的直流电压并以 RMS 计算直流电压

linux - SLURM - 回显输出文件以便在屏幕上打印?

python - 通过单词后面的第二个元音从字符串中获取子字符串

c++ - const char * 与其他指针不同吗?

c - 我的 makefile 出错,标志没有得到适当处理。可能是什么原因?

c - 从C中的动态数组中的特定位置删除元素