Sun Studio 12:Fortran 编程指南

11.1 兼容性问题

大多数 C-Fortran 接口必须在以下这些方面全部保持一致:

某些 C-Fortran 接口还必须符合:

11.1.1 函数还是子例程?

函数一词在 C 和 Fortran 中有不同的含义。根据具体情况做出选择很重要:

当 Fortran 例程调用 C 函数时:

当 C 函数调用 Fortran 子程序时:

11.1.2 数据类型的兼容性

表 11–2 总结了 Fortran 95(与 C 比较)数据类型的数据大小和缺省对齐。该表假设未应用影响对齐或提升缺省数据大小的编译选项。请注意以下事项:

表 11–1 数据大小与对齐-(以字节表示) 按引用传递(f95cc

Fortran 95 数据类型 

C 数据类型 

大小 

对齐 

BYTE x

char x

CHARACTER x

unsigned char x ;

 

CHARACTER (LEN=n) x

unsigned char x[n] ;

n

COMPLEX x

struct {float r,i;} x;

 

COMPLEX (KIND=4) x

COMPLEX (KIND=8) x

COMPLEX (KIND=16) x (SPARC)

struct {float r,i;} x;

struct {double dr,di;} x;

struct {long double, dr,di;} x;

16 

32 

4/8 

4/8/16 

DOUBLE COMPLEX x

struct {double dr, di;} x;

16 

4/8 

DOUBLE PRECISION x

double x ;

REAL x

float x ;

 

REAL (KIND=4) x

REAL (KIND=8) x

REAL (KIND=16) x (SPARC)

float x ;

double x ;

long double x ;

16 

4/8 

4/8/16 

INTEGER x

int x ;

 

INTEGER (KIND=1) x

INTEGER (KIND=2) x

INTEGER (KIND=4) x

INTEGER (KIND=8) x

signed char x ;

short x ;

int x ;

long long int x;

LOGICAL x

int x ;

 

LOGICAL (KIND=1) x

LOGICAL (KIND=2) x

LOGICAL (KIND=4) x

LOGICAL (KIND=8) x

signed char x ;

short x ;

int x ;

long long int x;

11.1.3 大小写敏感性

C 和 Fortran 在区分大小写方面采取截然相反的处理方法:

f95 缺省通过将子程序名转换成小写来忽略大小写。除了字符串常量以外,它会将所有大写字母都转换成小写字母。

对于大/小写问题,有两种常用解决方案:

只能采用这两种解决方案中的一种,不能同时采用。

本章大多数示例的 C 函数名均采用小写字母,并且没有使用 f95-U 编译器选项。

11.1.4 例程名中的下划线

Fortran 编译器通常会在入口点定义和调用中都出现的子程序名末尾追加一个下划线 (_)。该惯例不同于具有相同的用户指定名称的 C 过程或外部变量。几乎所有 Fortran 库过程名都有两个前导下划线,以减少与用户指定的子例程名的冲突。

对于下划线问题,有三种常用解决方案:

只能使用上述解决方案中的一种。

本章的示例都可以使用 BIND(C) 属性声明来避免下划线。BIND(C) 声明可从 Fortran 调用的 C 外部函数,以及可从 C 中作为参数调用的 Fortran 例程。Fortran 编译器在处理外部名称时通常不追加下划线。BIND(C) 必须出现在每个包含这样的引用的子程序中。惯常用法是:


       FUNCTION ABC
        EXTERNAL XYZ
        BIND(C) ABC, XYZ

在此处,用户不仅指定 XYZ 是外部 C 函数,而且还指定 Fortran 调用程序 ABC 应该可以从 C 函数调用。如果使用 BIND(C),C 函数不需要在函数名末尾追加下划线。

11.1.5 按引用或值传递参数

通常,Fortran 例程按引用传递参数。在调用中,如果非标准函数 %VAL() 中包含一个参数,则调用例程会按值传递该参数。

Fortran 95 按值传递参数的标准方法是通过 VALUE 属性和 INTERFACE 块。请参见 11.4 按值传递数据参数

C 通常按值传递参数。如果在参数前加上表示“和”的符号 (&),C 会使用指针按引用传递参数。C 总是按引用传递数组和字符串。

11.1.6 参数顺序

除字符串参数之外,Fortran 和 C 均以相同的顺序传递参数。但对于每个字符型参数,Fortran 例程都会传递一个附加参数,用以指定串长度。这些参数在 C 中是 long int 数量,按值进行传递。

参数顺序为:

示例:

Fortran 代码片段: 

等价的 C 代码片段: 


CHARACTER*7 S
INTEGER B(3)
...
 CALL SAM( S, B(2) )

char s[7];
int b[3];
...
sam_( s, &b[1], 7L ) ; 

11.1.7 数组索引和顺序

Fortran 与 C 的数组索引和顺序不同。

11.1.7.1 数组索引

C 数组总是从 0 开始,而 Fortran 数组在缺省情况下是从 1 开始。有两种常用的索引处理方法。


      INTEGER B(0:2)

这样,Fortran 元素 B(1) 就等同于 C 元素 b[1]

11.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 数组按行主顺序存储:A[3][2]


A[0][0] A[0][1] A[1][0] A[1][1] A[2][0] A[2][1]

这对于一维数组不存在任何问题。但对于多维数组,应注意下标在所有引用和声明中是如何出现和使用的-可能需要做些调整。

例如,在 C 中进行部分矩阵操作,而后在 Fortran 中完成余下部分,这样做可能会产生混淆。最好是将整个数组传递给另一语言中的例程,然后在该例程中执行所有矩阵操作,以避免在 C 和 Fortran 中各执行部分操作的情况。

11.1.8 文件描述符和 stdio

Fortran I/O 通道采用的是单元号。底层 SunOS 操作系统不处理单元号,而是处理文件描述符。Fortran 运行时系统会不断变换,所以大多数 Fortran 程序没必要识别文件描述符。

许多 C 程序都使用一组称为标准 I/O(即 stdio)的子例程。有许多 Fortran I/O 函数也使用标准 I/O,而后者又使用操作系统 I/O 调用。下表列出了这些 I/O 系统的某些特性。

表 11–2 Fortran 与 C 之间的 I/O 比较

 

Fortran 单元 

标准 I/O 文件指针 

文件描述符 

文件打开 

为读写打开 

为读打开、为写打开、为读写打开,或者为追加打开;请参见 open(2)

为读打开、为写打开或同时为读写打开 

属性 

已格式化或未格式化 

始终未格式化,但可用格式解释例程进行读或写 

始终未格式化 

访问 

直接或顺序 

直接访问(如果物理文件的表示是直接访问),但总是可以按顺序读取 

直接访问(如果物理文件的表示是直接访问),但总是可以按顺序读取 

结构 

记录 

字节流 

字节流 

形式 

0-2147483647 间的任意非负整数 

指向用户地址空间中结构的指针 

0-1023 间的整数 

11.1.9 库与使用 f95 命令链接

要链接正确的 Fortran 和 C 库,请使用 f95 命令调用链接程序。

示例 1:用编译器进行链接:


demo% cc -c someCroutine.c
demo% f95 theF95routine.f someCroutine.o  <- 链接步骤
demo% a.out
 4.0 4.5
 8.0 9.0
demo%