fortran与c语言接口参数传递混合编程.docx

上传人:牧羊曲112 文档编号:4884620 上传时间:2023-05-21 格式:DOCX 页数:30 大小:138.85KB
返回 下载 相关 举报
fortran与c语言接口参数传递混合编程.docx_第1页
第1页 / 共30页
fortran与c语言接口参数传递混合编程.docx_第2页
第2页 / 共30页
fortran与c语言接口参数传递混合编程.docx_第3页
第3页 / 共30页
fortran与c语言接口参数传递混合编程.docx_第4页
第4页 / 共30页
fortran与c语言接口参数传递混合编程.docx_第5页
第5页 / 共30页
亲,该文档总共30页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《fortran与c语言接口参数传递混合编程.docx》由会员分享,可在线阅读,更多相关《fortran与c语言接口参数传递混合编程.docx(30页珍藏版)》请在三一办公上搜索。

1、Sun Studio 12: Fortran 编程指南Previous:第10章并行化第 11 章 C-Fortran 接口本章论述Fortran与C的互操作性方面的问题,内容仅适用于Sun Studio Fortran 95 和C编译器的特定情况。11.9 Fortran 2003与C的互操作性简要说明了 Fortran 2003标准第15部分中提 到的C绑定功能。(此标准可以从国际Fortran标准Web站点获得)。Fortran 95 编译器实现了标准中所述的这些功能。如不特别注明,32位x86处理器视为与32位SPARC处理器等同。对于64位 x86处理器和64位SPARC处理器也是如

2、此,只是x86系统未定义REAL*16和 COMPLEX*32数据类型,这些数据类型只能用于SPARCo11.1兼容性问题大多数C-Fortran接口必须在以下这些方面全部保持一致: 函数和子例程的定义及调用 数据类型的兼容性 参数传递(按引用或按值) 参数的顺序 过程名(大写、小写或带有结尾下划线(_) 向链接程序传递正确的库引用某些C-Fortran接口还必须符合: 数组索引及顺序 文件描述符和stdio 文件权限11.1.1函数还是子例程?函数一词在C和Fortran中有不同的含义。根据具体情况做出选择很重要:在C中,所有的子程序都是函数;但void函数不会返回值。在Fortran中,函

3、数会传递一个返回值,但子例程一般不传递返回值。当Fortran例程调用C函数时: 如果被调用的C函数返回一个值,则将其作为函数从Fortran中调用。 如果被调用的C函数不返回值,则将其作为子例程调用。当C函数调用Fortran子程序时: 如果被调用的Fortran子程序是一个函数,则将其作为一个返回兼容数据类型 的函数从C中调用。 如果被调用的Fortran子程序是一个子例程,则将其作为一个返回int (与Fortran INTEGER*4兼容)或void值的函数从C中调用。如果Fortran子 例程使用交替返回,则会返回一个值,这种情况下它是RETURN语句中的表达 式的值。如果RETUR

4、N语句中没有出现表达式,但在SUBROUTINE语句中声 明了交替返回,则会返回零。11.1.2数据类型的兼容性表112总结了 Fortran 95 (与C比较)数据类型的数据大小和缺省对齐。该表假设 未应用影响对齐或提升缺省数据大小的编译选项。请注意以下事项: C数据类型int、long int和long在32位环境下是等同的(4字节)。 但是,在64位环境下long和指针为8字节。这称为LP64数据模型。 在64位SPARC环境下,当用任意m64选项进行编译时, REAL*16和COMPLEX*32与16字节边界对齐。 标有4/8的对齐表示缺省情况下与8字节边界对齐,但在COMMON块中与

5、 4字节边界对齐。COMMON中的最大缺省对齐为4字节。当用m64选项进 行编译时,4/8/16表示与16字节边界对齐。 REAL(KIND=16)、REAL*16、COMPLEX(KIND=16)、COMPLEX*32 只 能用于SPARC平台。 数组和结构的元素及字段必须兼容。 不能按值传递数组、字符串或结构。 可以在调用点使用VAL(arg),按值将参数从Fortran 95例程传递到C例 程。假如Fortran例程具有一个显式接口块,该接口块用VALUE属性声明了伪 参数,则可以按值将参数从C传递到Fortran 95。 数值序列类型的组件的对齐方式与通用块的对齐方式相同,也会受到al

6、igncommon选项的影响。数值序列类型是这样一种序列类型:其中所 有组件的类型为缺省整数、缺省实数、双精度实数、缺省复数或缺省逻辑,而不 是指针。 在大多数情况下,非数值序列类型的数据类型组件以自然对齐的方式对齐,但 QUAD变量除外。对于四精度变量,32位SPARC平台和64位SPARC平 台之间的对齐方式不同。 在所有平台上,用BIND(C)属性定义的VAX结构和数据类型的组件始终与 C结构具有相同的对齐方式。表11 -数据大小与对齐一(以字节表示)按引用传递(f95和cc)1Fortran 95数据类型C数据类型大小对齐1 BYTE xchar x111CHARACTER xunsi

7、gned char x ;111CHARACTER (LEN=n) xunsigned char xn;n11COMPLEX xstruct float r,i; x;841COMPLEX (KIND=4) xCOMPLEX (KIND=8) xCOMPLEX (KIND=16)x (SPARC)struct float r,i; x;struct double dr,di; x;struct long double, dr,di; x;8163244/84/8/161 DOUBLE COMPLEX xstruct double dr, di; x;164/81 DOUBLE PRECISIO

8、N xdouble x ;841 REAL xfloat x ;441REAL (KIND=4) xREAL (KIND=8) xREAL (KIND=16)x (SPARC)float x ;double x ;long double x ;481644/84/8/161INTEGER xint x ;441INTEGER (KIND=1) xsigned char x ;141Fortran 95数据类型C数据类型亲对齐1INTEGER (KIND=2) xshort x ;24INTEGER (KIND=4) xint x ;44INTEGER (KIND=8) xlong long i

9、nt x;841 LOGICAL xint x ;441LOGICAL (KIND=1) xsigned char x ;14LOGICAL (KIND=2) xshort x ;24LOGICAL (KIND=4) xint x ;44LOGICAL (KIND=8) xlong long int x;8411.1.3大小写敏感性C和Fortran在区分大小写方面采取截然相反的处理方法: C区分大小写一大小写很重要。 Fortran在缺省情况下忽略大小写。f95缺省通过将子程序名转换成小写来忽略大小写。除了字符串常量以外,它会将所有 大写字母都转换成小写字母。对于大/小写问题,有两种常用解决

10、方案: 在C子程序中,使C函数名全为小写。 用-U选项编译Fortran程序,该选项会通知编译器保留函麴子程序名称的现 有大/小写区别。只能采用这两种解决方案中的一种,不能同时采用。本章大多数示例的C函数名均采用小写字母,并且没有使用f95-U编译器选项。11.1.4例程名中的下划线Fortran编译器通常会在入口点定义和调用中都出现的子程序名末尾追加一个下划线 (_)。该惯例不同于具有相同的用户指定名称的C过程或外部变量。几乎所有Fortran 库过程名都有两个前导下划线,以减少与用户指定的子例程名的冲突。对于下划线问题,有三种常用解决方案: 在C函数中,通过在函数名末尾追加下划线来更改该名

11、称。 使用BIND(C)属性声明来指明外部函数是C语言函数。 使用f95ext_names选项编译对无下划线的外部名称的引用。只能使用上述解决方案中的一种。本章的示例都可以使用BIND(C)属性声明来避免下划线。BIND(C)声明可从 Fortran调用的C外部函数,以及可从C中作为参数调用的Fortran例程。Fortran 编译器在处理外部名称时通常不追加下划线。BIND(C)必须出现在每个包含这样的引 用的子程序中。惯常用法是:在此处,用户不仅指定XYZ是外部C函数,而且还指定Fortran调用程序ABC应该 可以从C函数调用。如果使用BIND(C),C函数不需要在函数名末尾追加下划线。

12、11.1.5按引用或值传递参数通常,Fortran例程按引用传递参数。在调用中,如果非标准函数%VAL()中包含一个 参数,则调用例程会按值传递该参数。Fortran 95按值传递参数的标准方法是通过VALUE属性和INTERFACE块。请参 见11.4按值传递数据参数。C通常按值传递参数。如果在参数前加上表示和”的符号(&),C会使用指针按引用传 递参数。C总是按引用传递数组和字符串。11.1.6参数顺除字符串参数之外,Fortran和C均以相同的顺序传递参数。但对于每个字符型参数, Fortran例程都会传递一个附加参数,用以指定串长度。这些参数在C中是long int数量,按值进行传递。

13、参数顺序为:与每个参数相应的地址(数据或函数)与每个字符参数对应的long int (字符串长度的完整列表位于其他参数的完 整列表之后)示例:Fortran代码片段:等价的C代码片段:char s7;int b3;CHARACTER*? S INTEGER B(3)CALL SAM( S, B(2)sam ( s, &b1, 7L );11.1.7数组索引和顺序Fortran与C的数组索引和顺序不同。11.1.7.1数组索引C数组总是从0开始,而Fortran数组在缺省情况下是从1开始。有两种常用的索 引处理方法。 如上述示例所示,可以使用Fortran缺省设置。此时,Fortran元素B(2

14、)等 同于C元素b1。 可以指定Fortran数组B以B(0)开始,如下所示:INTEGER B(0:2)这样,Fortran元素B(1)就等同于C元素b111.1.7.2数组顺序Fortran数组按列主顺序存储:A(3,2)A(1,1)A(2,1)A(3,1)A(1,2)A(2,2)A(3,2)C数组按行主顺序存储:A32A00 A01 A10 A11 A20 A21 这对于一维数组不存在任何问题。但对于多维数组,应注意下标在所有引用和声明中是 如何出现和使用的一可能需要做些调整。例如,在C中进行部分矩阵操作,而后在Fortran中完成余下部分,这样做可能会产 生混淆。最好是将整个数组传递给

15、另一语言中的例程,然后在该例程中执行所有矩阵操 作,以避免在C和Fortran中各执行部分操作的情况。11.1.8文件描述符和stdioFortran I/O通道采用的是单元号。底层SunOS操作系统不处理单元号,而是处理文 件描述符。Fortran运行时系统会不断变换,所以大多数Fortran程序没必要识别文件 描述符。许多C程序都使用一组称为标准I/O (即stdio)的子例程。有许多Fortran I/O函 数也使用标准I/O,而后者又使用操作系统I/O调用。下表列出了这些I/O系统的某 些特性。表11 2 Fortran与C之间的I/O比较1Fortran 单元标准I/O文件指针文件描

16、述符I文件 打 开为读写打开为读打开、为写打开、为 读写打开,或者为追加打开;请参见 open (2)为读打开、为写打开 或同时为读写打 开1属性己格式化或未格 式化始终未格式化,但可用格 式解释例程进行读或写始终未格式化1访问直接或顺序直接访问(如果物理文件 的表示是直接访问),但 总是可以按顺序读取直接访问(如果物理 文件的表示是直接 访问),但总是可以 按顺序读取1结构记录字节流字节流1形式0-2147483647 间 的任意非负整 数指向用户地址空间中结构 的指针0-1023间的整数11.1.9库与使用f95命令链接要链接正确的Fortran和C库,请使用f95命令调用链接程序。示例1

17、:用编译器进行链接:demo% cc -c someCroutine.cdemo% f95 theF95routine.f someCroutine.o r = 32.;w - i = .007;z - r = 66.67;z - i = 94.1;在64位 环境下,在寄存器中返回COMPLEX值。11.3.3字符串由于没有标准接口,因此不推荐在C与Fortran例程间传递字符串。不过,请注意以 下方面: 所有C字符串均按引用传递。 Fortran调用会为参数列表中具有字符类型的每个参数传递一个附加参数。此额 外参数给出串长度,它等同于按值传递的C长整数。(这要依具体实现而定。) 额外的串长度

18、参数出现在调用中的显式参数之后。下例展示了具有字符串参数的Fortran调用及其等同的C调用:1Fortran 调用:等价的C调用:I1INTEGER B(3)int b3;. CALL CSTRNG( S, B(2). . cstrng_( s, &b1, 7L ); 如果在被调用例程中不需要串长度,则可以忽略额外的参数。但要注意,Fortran不会 自动以C期望的显式空字符来终结字符串。该终结符必须由调用程序添加。字符数组调用与单个字符变量调用看起来一样。会传递数组的起始地址,所使用的长度 是数组中单个元素的长度。11.3.4 一维数组在C中数组下标以0开始。表11 6传递一维数组1For

19、tran 调用 CC 调用 Fortran1integer i, Sum integer a(9) external FixVec call FixVec ( a, Sum ) extern void vecref_(int, int * ); int i, sum;int v9 = vecref_( v, &sum ); void fixvec_ ( int v9, int *sum ) int i;*sum = 0;subroutine VecRef( v, total)integer i, total, v(9)total = 011.3.5二维数组C与Fortran间的行列转换。表11

20、 7传递二维数组Fortran 调用 CC 调用 FortranREAL Q(10,20)extern voidQ(3,5) = 1.0qref_( int10, int *);CALL FIXQ(Q)int m2010=int sum;qref_( m, &sum );void fixq_( float a2010)a53 =a53 +1.;SUBROUTINE QREF(A,TOTAL)INTEGERA(10,20), TOTALDO I = 1,10DO J = 1,20TOTAL = TOTAL + A(I,J)END DO11.3.6结构只要相应的元素是兼容的,便可以将C和Fortr

21、an 95派生类型传递给彼此的例程。(f95接受传统的STRUCTURE语句。)表11 8传递传统FORTRAN 77 STRUCTURE记录Fortran 调用 CC 调用 FortranSTRUCTURE /POINT/REAL X, Y, ZEND STRUCTURERECORD /POINT/ BASEEXTERNAL FLIP CALL FLIP( BASE )struct point float x,y,z;void fflip_ ( struct point*); 一struct point d;struct point *ptx = &d;. fflip (ptx);struc

22、t point float x,y,z;SUBROUTINE FFLIP(P) STRUCTURE /POINT/ REAL X,Y,Z END STRUCTURE RECORD /POINT/ P REAL T;void flip_( struct point*v )float t;t = v - x;v - x = v - y;1Fortran 调用 CC 调用 Fortran1v - y = t;T = P.Xv- z = -2.*(v - z);P.X = P.YP.Y = TP.Z = -2.*PZ.请注意,在所有平台上Fortran 77 (VAX)结构与C结构的对齐方式始终相同。

23、但是, 平台之间对齐方式会有所变化。表119传递Fortran 95派生类型Fortran 95 调用 CC 调用 Fortran 95TYPE pointSEQUENCEREAL : x, y, z END TYPE point TYPE (point) base EXTERNAL flip. CALL flip( base)struct point float x,y,z;extern void fflip_ ( struct point *); struct point d;struct point *ptx = &d; fflip (ptx);struct point float x,

24、y,z;void flip_( struct point*v ) x;v - x = v - y;v - y = t;v - z = -2.*(v - z);请注意,Fortran 95标准要求派生类型定义中有SEQUENCE语句,以确保编译器保持 存储序列的顺序。在所有平台上,数值序列类型的组件缺省情况下与字(4字节)边界对齐。这与x86平 台上C结构的对齐方式相匹配,但是不同于SPARC平台上C结构的对齐方式。使 用-aligncommon选项可更改数值序列类型的对齐方式,以便与C结构相匹配。使 用-aligncommon=8 匹配 32 位 SPARC C 结构,使用-aligncomm

25、on=16 匹 配 64 位 SPARCo未使用SEQUENCE显式声明的派生类型与SPARC平台上的C结构对齐方式相同, 但与x86平台上的对齐方式不同。这种对齐方式不随编译器选项而改变。11.3.7指针由于Fortran例程按引用传递参数,因此可将FORTRAN 77 (Cray)指针作为指针的 指针传递给C例程。表 11-0 传递 FORTRAN 77 (Cray)指针1Fortran 调用 CC 调用 Fortran1REAL Xextern voidPOINTER (P2X, X)fpass_( float* );EXTERNAL PASS.P2X = MALLOC(4)float

26、*p2x;X = 0.CALL PASS(P2X)fpass (&p2x);void pass_(p) float *p;*p = 100.1;SUBROUTINE FPASS (P2X) REAL X POINTER (P2X, X) X = 0.C指针与Fortran 95标量指针兼容,但与数组指针不兼容。Fortran 95用标量指针调用CFortran 95 例程:INTERFACE SUBROUTINE PASS(P)REAL, POINTER : P END SUBROUTINEEND INTERFACEREAL, POINTER : P2XALLOCATE (P2X)P2X =

27、0CALL PASS(P2X)PRINT*, P2XENDCray与Fortran 95指针间的主要区别是Cray指针的目标始终是已命名的。在许多 上下文中,声明Fortran 95指针会自动标识其目标。另外,被调用C例程还需要显 式 INTERFACE 块。要将Fortran 95指针传递给数组或数组段,需要特定的INTERFACE块,如下例所示:Fortran 95 例程:INTERFACESUBROUTINE S(P)integer P(*)END SUBROUTINE SEND INTERFACEinteger, target: A(0:9)integer, pointer : P(:

28、)P = A(0:9:2) ! pointer selects every other element of A call S(P) C例程:void s (int p)请注意,由于C例程S不是Fortran 95例程,因此不能在接口块中将其定义成假定 的形状(integer P(:)。如果C例程需要知道数组的实际大小,必须将其作为参 数传递给C例程。另请注意,C与Fortran间的下标编排不同,C数组以下标0开始。11.4按值传递数据参数从C中调用时,Fortran 95程序应在伪参数中使用VALUE属性,并且应为从Fortran 95中调用的C例程提供一个INTERFACE块。表11-1在

29、C与Fortran 95之间传递简单数据元素Fortran 95 调用 CC 调用 Fortran 95PROGRAM callcINTERFACEINTEGER FUNCTION crtn(I)BIND(C) crtnINTEGER, VALUE, INTENT(IN) : IEND FUNCTION crtnEND INTERFACEM = 20MM = crtn(M)WRITE (#include int main(int ac, char Fortran 例程:,*) M, MM END PROGRAMENDint crtn(int x)int y;printf(%d input n,

30、 x);y = x + 1;printf(%d returning n,y);return(y);Results:20 input21 returning20 21请注意,如果要以不同的数据类型作为实际参数来调用C例程,应该在接口块中包 含!$PRAGMA IGNORE_TKR I,以防止编译器在实际参数和伪参数之间要求类型、 类别和等级匹配。对于传统Fortran 77,按值调用仅对简单数据可用,并且只能为调用C例程的Fortran 77例程所用。无法做到让C例程调用Fortran 77例程并按值传递参数。数组、字符 串或结构最好是按引用传递。要将值从Fortran 77例程传递到C例程,请

31、使用非标准Fortran函数%VAL(arg)作为调用中的一个参数。在以下示例中,Fortran 77例程按值传递x,按引用传递y。C例程同时增加了 x和 y,但只有y发生了改变。Fortran 调用 CREAL x, y x = 1. y = 0. PRINT *, x,y CALL value( %VAL(x), y) PRINT *, x,y ENDC例程:void value_( float x, float *y) printf(%f, %fn,x,*y);x = x + 1.;*y = *y + 1.;printf(%f, %fn,x,*y);编译并运行会产生以下输出结果:1.00

32、000 0.x and y from Fortran1.000000, 0.000000 x and y from C2.000000, 1.000000 new x and y from C1.00000 1.00000 new x and y from Fortran11.5返回值的函数返回 BYTE、INTEGER、REAL、LOGICAL、DOUBLE PRECISION 或 REAL*16 类型值的Fortran函数与返回兼容类型的C函数是等同的(请参见表11 -)。字符型函数的返回值存在两个额外参数,复数型函数的返回值存在一个额外参数。11.5.1返回简单数据类型下例返回一个 RE

33、AL 或 float 值。BYTE、INTEGER、LOGICAL、DOUBLEPRECISION和REAL*16的处理方式类似:表11-2返回REAL或Float值的函数 Fortran 调用 CC 调用 Fortranreal ADD1, R, S external ADD1 R = 8.0 S = ADD1( R )float r, s;extern float fadd1_() ; r = 8.0;s = fadd1( &r );float add1_( pf ) float *pf;float f ;f = *pf;f+;return ( f );real function fadd

34、1 (p) real p fadd1 = p + 1.0 returnend11.5.2 返回 COMPLEX 数据COMPLEX数据的互操作性情况在SPARC 32位和64位实现之间有所不同。11.5.2.1 32 位平台在32位平台上,返回COMPLEX或DOUBLE COMPLEX的Fortran函数等同于 具有一个指向内存中返回值的附加第一参数的C函数。Fortran函数及其相应的C函 数的一般样式如下:COMPLEX FUNCTIONCF( a1,a2,.,an)cf_ (return, al, a2,. an)struct float r, i; * return表11-3返回CO

35、MPLEX数据的函数(32位SPARC)Fortran 调用 CC 调用 FortranCOMPLEX U, V, RETCPXEXTERNAL RETCPXU = ( 7.0, -8.0)V = RETCPX(U)struct complex float r, i; ;struct complex c1, c2; r = 7.0;u - i = -8.0;retfpx ( v, u );struct complex float r, i; ;void retcpx_( temp, w ) struct complex *temp, *w; temp-r = w-r + 1.0; temp-i

36、 = w-i + 1.0; return;COMPLEX FUNCTION RETFPX(Z) COMPLEX Z RETFPX = Z + (1.0, 1.0) RETURNEND11.5.2.2 64 位 SPARC 平台在64位SPARC环境下,在浮点寄存器中返回COMPLEX值:在%f0和%f1中返回 COMPLEX 和 DOUBLE COMPLEX,在f0、f1、%f2 和 %f3 中返回COMPLEX*32。对于64位SPARC,返回结构(其字段均为浮点型)的C函数将在浮点寄存器中返回该结构,但条件是最多需要4个这样的寄存器进行此操作。在64位SPARC平台上,Fortran函数及

37、其相应的C函数的一般样式如下:Fortran 函数C函数COMPLEX FUNCTION CF(a1, a2, ., an)struct float r,i; cf_ (a1, a2, ., an)表11-4返回COMPLEX数据的函数(64位SPARC)Fortran 调用 CCOMPLEX U, V, RETCPXEXTERNAL RETCPXU = ( 7.0, -8.0)V = RETCPX(U)struct complex float r, i; ;struct complex retcpx_(struct complex *w ) struct complex temp;temp.

38、r = w-r + 1.0;temp.ii = w-i + 1.0;return (temp);C 调用 Fortranstruct complex float r, i; ; struct complex c1, c2;struct complex *u=&c1;extern struct complex retfpx_(struct complex *);u - r = 7.0;u - i = -8.0;retfpx ( u );COMPLEX FUNCTION RETFPX(Z) COMPLEX Z RETFPX = Z + (1.0, 1.0) RETURNEND11.5.3 返回 CHARACTER 串不鼓励在C与Fortran例程之间传递字符串。但是,具有字符串值的Fortran函数等 同于具有两个附加第一参数(数据地址和串长度)的C函数。Fortran函数及其相应 的C函数的一般样式如下:CHARACTER*n FUNCTION C(a1, ., an)Fortra

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号