【发布时间】: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)是干什么的。