【问题标题】:Fortran variable getting overwritten when linked with C function与 C 函数链接时,Fortran 变量被覆盖
【发布时间】:2014-02-24 18:41:14
【问题描述】:

我在一些旧版 fortran 中添加了一个数据收集例程。为了方便使用,我用 C 编写了文件 i/o 例程。

我正在使用 gcc 和 gfortran。

问题:在看似无害的 C 函数调用过程中,一些 fortran 变量名称被覆盖。

C 函数都是 void 类型,名称都是小写字母,所有参数都是指针,函数名称都包含结尾的“_”,并且作为子例程从 Fortran 调用。我以前做过。 gfortran 强制所有 Fortran 符号为小写,并且所有入口点都附加一个“_”以区别于同名 C 入口点。

这是 C 文件的一个片段:

#define MAXFILES 20
FILE *outfile[MAXFILES];

/* int2char_ generates a left zero padded string (*theChar) from an int
   (*theInt), that is *numChar characters long.  E.g, called from fortran:

   string *5 arun
   integer nrun
   integer nnchar

   nrun = 231
   nchar = 4
   call int2char (nrun, arun, nnchar)
c...   returns '0231' in arun
*/
void int2char_ (int *theInt, char *theChar, int *numChar) {

  int nchar;

  nchar = *numChar;

  if (nchar > 9) nchar = 9;
  if (nchar < 1) nchar = 1;

  sprintf(theChar, "%*.*d", nchar, nchar, *theInt);

  return;
}  // end of int2char


void openwrite_ (char *filename, int *unit) {
  outfile[*unit] = fopen (filename, "w");
  return;
}  /* end of openWrite */

void closefile_ (int *unit) {
  int closed;
  if (outfile[*unit]) {
    closed = fclose (outfile[*unit]);
  }
  return;
}

void writefirststr_ (char *string, int *unit) {
  int printed;
  printed = fprintf (outfile[*unit], "%s", string);
//  printed = fputs (string, outfile[*unit]);
  return;
}

这是被踩到的 Fortran 变量的声明:

c...................
c"Display the mass matrix when DISMAT is set TRUE "
      LOGICAL, save :: DISMAT
c...................

注意:我最初使用 volatile 声明限定符代替了 save 限定符。没有区别。

来电:

c...................
c...  build file name
          numchar = 4
          call int2char (nrun, filenumber, numchar)
          begin = 1
          end = len_trim(fileprefix)
          filename(begin:end) = fileprefix

          begin = end + 1
          end = begin + 3
          filename(begin:end) = filenumber

          begin = end + 1
          end = begin + 3
          filename(begin:end) = fileext

          begin = end + 1
          filename(begin:begin) = char(0)


c...  close open file
          call closefile (lunit)

c...  open file
          call openWrite (filename, lunit)

c...  write header(s)
          call writeFirstStr (atime', lunit)
c...................

当我执行call writefirstStr ('time', lunit) 行时出现问题。

atime 是一个character*5,它被数据化为“时间”,并由time(5:) = char(0) 显式终止。单步执行writefirststr_() 显示没有问题,并且将正确的信息写入文件。

如果我在call openWrite (filename, lunit) 之后(通过gdb)跳转到return 语句(在包含上述代码片段的fortran 例程中),则没有问题。

调用writeFirstStr 会覆盖fortran 变量DISMAT。我还应该注意,DISMAT 不在上面进行 C 语言调用的例程中。

我还没有尝试过在所有 Fortran 变量上使用 save 限定符 - 由于遗留代码的数量导致后勤问题。

有人有什么想法吗?

【问题讨论】:

  • 一般来说,你应该使用ISO_C_BINDING模块来结合C和Fortran。
  • 我支持使用 ISO_C_BINDING 的建议。这样您就不必弄清楚特定编译器对的参数传递约定,并且实现将是可移植的。
  • 在谈到iso_c_binding 模块时,我要小心,尤其是对初学者来说,因为仅仅使用它根本不会改变代码的行为(尤其是隐藏的参数)。 bind(C) 是干什么的。

标签: c fortran mixed


【解决方案1】:

在我看来,调用约定有问题。您正在传递一个字符变量。 Fortran 通常使用隐藏变量作为字符串长度。

你的void writefirststr_没有这样的参数。

对于 CHARACTER 类型的参数,字符长度作为 隐藏的论点。对于延迟长度字符串,该值通过 参考,否则按价值。字符长度有类型 整数(种类=4)。注意 C 绑定,CHARACTER(len=1) 结果 变量根据平台ABI返回,无隐藏 长度参数用于虚拟参数;与价值,那些 变量按值传递。

(来自http://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html#Argument-passing-conventions

对于任何新的 Fortran 代码,我始终建议使用现代 Fortran 与 C (bind(C)) 和 iso_c_binding 内在模块的互操作性。

【讨论】:

    【解决方案2】:

    我认为,您的代码存在几个问题:

    sprintf(theChar, "%*.*d", nchar, nchar, *theInt);
    

    格式字符串应为“%*d”,因为您只能传递一个整数作为整数的精度。

    下一个问题是 Fortran 的错误记录“功能”。 Fortran 将字符串的大小作为隐藏参数传递到所有变量的末尾(这次是按值而不是按指针)。

    你的函数应该是这样的:

    void int2char_ (int *theInt, char *theChar, int *numChar, long len_of_the_char);
    void writefirststr_ (char *string, int *unit, long len_of_string);
    

    长度变量的顺序与传递字符串的顺序相同。长度变量的数据类型取决于编译器和操作系统。 注意 Fortran 90 和显式接口。显式接口可能会抑制此附加参数。

    如果您尝试关闭一个单元,而之前没有打开,则可能会出现下一个问题。您没有初始化全局数组(或者您没有发布代码;-))

    删除了该条目的其余部分(感谢 Vladimir F)。

    【讨论】:

    • "atime 是一个 character*5,它被数据化为 'time' 并由 time(5:) = char(0) 显式地以 null 终止。"
    • 我没有在 Fortran 字符串中找到有关“a”前缀的内容,所以我猜它一定是拼写错误 ;-) 不知何故,我不认为字符串长度的被遗忘参数导致崩溃,因为它是传递的最后一个变量,Fortran 将其放入堆栈并在函数返回后将其删除。我知道一些情况,当它没有崩溃时,当它崩溃时没有情况......知道问题出在哪里会很有趣。
    猜你喜欢
    • 2014-04-30
    • 2010-11-17
    • 1970-01-01
    • 2016-09-18
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    相关资源
    最近更新 更多