这篇文档主要是对C和Fortran的混合编程实现进行一个大致的学习与归纳。目前在work中主要是利用Fortran调用C函数。
基本概况
由于 GNU 的 Fortran 和 C 语言二者的函数彼此可以直接相互调用,所以混合编程可以非常容易地实现。只要你足够仔细,确保函数调用时传递的参数类型正确,函数就可以在两种语言间来回调用,就像它们是同一种语言一样。
下表中列出了 Fortran 的数据类型和它们在 C 中对应的类型。这张表在大多数平台下是没问题的,但是或许会有例外的情况发生。在你打算传递某种数据类型时,先编写一个简单的例子进行测试将是很明智的。
注意:
由于 Fortran 总是以引用的方式传递参数,而 C 则始终以地址方式传递数组,因此数组做参数时不需做任何修改。但是对多维数组来说,混合调用时其下标需要翻转,因为 Fortran 的数组是以列为主序(column-major order)而 C 数组以行为主序(row-major order)。
实例分析
简单案例
Fortran调用C函数
主程序
1234567891011121314! C 表示注释C fortran2c.fCPROGRAM FORTRAN2CCCHARACTER*32 HELLOREAL PICHELLO = "Hello C from Fortran"HELLO(21:21) = CHAR(0)C HELLO(21) = CHAR(0)PI = 3.14159CALL SHOWHIPI(HELLO,PI)END PROGRAM FORTRAN2CTips:
- 可存储32个字符的 CHARACTER 型字符串变量 HELLO 中,存有 21 个字符,剩余部分用空格填充。
- 要将该字符串格式化为 C 语言标准的字符串,我们必须在实际字符串结束的位置插入一个 ascii 码为“0”字符作为结束标志。
- REAL 型浮点数 PI 存储方式和 C 中 float 型变量完全一样,因此可以直接传递给函数。
- 理解 Fortran 的参数总是通过引用传递是非常重要的,因此 C 函数接收到的总是被传递的变量的地址而不是变量值本身。
调用程序
123456/* showhipi.c */void showhipi_(char *string,float *pi){printf("%s\nPI=%f\n",string,*pi);}Tips:
- 在不同的平台下 Fortran 和 C 语言的命名惯例和数据类型的匹配关系是不同的。如同你在本例中看到的,在函数名后添加一下划线是必须的。
编译运行
12345$ gfortran -c fortran2c.f -o fortran2c.o$ gcc -c showhipi.c -o showhipi.o$ gfortran fortran2c.o showhipi.o -o fortran2c# OR$ gcc fortran2c.o showhipi.o -o fortran2c -lgfortranbegin -lgfortranTips:
- gfortran只是gcc的一个前端
C调用Fortran函数
主程序
12345678910111213/* c2fortran.c */int main(int argc,char *argv[]){int i;float e = 2.71828;char hello[32];int length = sizeof(hello);strcpy(hello,"Hello Fortran from C");for(i=strlen(hello); i<length; i++)hello[i] = ' ';showhie_(hello,&length,&e);return(0);}Tips:
- 在 C 中,字符串的长度是由 null 字符的位置决定的,但在 Fortran 中,所有字符串的长度都是固定的。
- 由于 Fortran 没有办法确定传递给它字符串的长度,我们必须将字符串长度作为参数同时传递。本例中,字符数组用空格填充,数组大小作为第二个参数传递。
- 注意到三个参数都是通过指针传递的──因为 Fortran 总是期待地址而不是真实的值。
- 在被调用的子程序名后添加一下划线通常是必须的。
调用程序
1234567891011C showhie.fCSUBROUTINE SHOWHIE(HELLO,LENGTH,E)CHARACTER*(*) HELLOINTEGER LENGTHREAL ECWRITE(*,100) HELLO(1:LENGTH),LENGTH,E100 FORMAT(3X,A,2X,I3,4X,F6.4)RETURNEND SUBROUTINE SHOWHIE编译运行
12345$ gfortran -c showhie.f -o showhie.o$ gcc -c c2fortran.c -o c2fortran.o$ gfortran c2fortran.o showhie.o -o c2fortran# OR$ gcc fortran2c.o showhipi.o -o fortran2c -lgfortranbegin -lgfortran
重点探讨
混合语言编程要注意的问题主要体现在: 函数调用和数据结构的存储。
注意及范例
注意事项:
- 在C与Fortran中数组存放顺序不同,因此,传送后必须进行转置
- 在C中数组元素下标从0开始,而在Fortran中则从1开始
- 在C与Fortran中传递的数组大小、类型必须完全相同、对应
- 在C中,形参中的数组元素不能采用动态数组,即不能用malloc分配内存
数组顺序
|
|
元素下标
|
|
其他
|
|
函数调用
- 对于有返回值调用,二者的返回值数据类型必须一致。
- Fortran调用例程时,实参和形参默认是引用传递,而C则是值传递。
- 如果二者均采用默认的调用方式,那么Fortran调用C函数 时,C的形参应该声明为指针类型(*);C调用Fortran函数时,C传递实参时须以&形式传递变量地址。
- 传递数组时,二者均使用数组首地址作为参数,因此无需转换。如果C的参数本身为指针变量,也不需要转换。
参考: