2013-07-17 69 views
3

我从FORTRAN 90代码调用C例程。所有的工作都很好,但我想知道为什么和如何用更少的参数调用C程序,我应该让编译器不抱怨。编译器在这里做什么?我正在使用Cray编译器。不同数目的参数调用C例程从FORTRAN 90

test.c的

extern "C" void test_(double* x, double* y, double* z){ 
    // do some work 
} 

driver.F90

MODULE DRIVER 

! declare arrays 
DOUBLE PRECISION, DIMENSION(dim, dim), INTENT(IN) :: x 
DOUBLE PRECISION, DIMENSION(dim, dim), INTENT(IN) :: y 

! call C subroutine 
CALL test(x, y) 

END MODULE DRIVER 
+0

可能的测试函数会弹出一个未定义的值,表示Fortran没有推入堆栈(或将null可能为零)。例子:push x,y,z pop z,y,x但是没有做最新的push,所以它是push x,y pop z(它是y),y(它是x),undefined x(没有push/null) –

+2

在你的C打印z方法并找出答案。由于每个编译器都不同,因此在调用外部方法时应始终确保传入正确的编号参数。它要么将z设置为默认值(零或空值),要么会损坏堆栈,并且您将遇到一些内存问题,可能会显示更多内容...... – MoonKnight

+1

我不相信这是downvoted。 –

回答

8

Fortran语言是比C一个很大的不同,当涉及到函数调用。当传递参数给C例程,编译器必须知道每个参数的类型,以便它可以生成相应的调用序列 - 要么把参数堆栈上以正确的顺序并用正确的填充或把他们的预期寄存器。如果在调用者之前定义了被调用者,那么C编译器通常在编译代码时收集这些信息。在所有其他情况下,应提供原型形式的函数声明。

Fortran中所有参数通常是(有一些例外)的转交地址,这意味着什么是真正被传递给被叫方是一组内存指针。指针看起来是一样的 - 它们总是相同的类型,因此以相同的方式传递。因此,Fortran编译器可以在不知道被调用者实际期望的参数的情况下生成函数调用。这大大简化了Fortran编译器,但随后可能出现的错误的无数的来源,比如调用函数与错误的参数类型或者即使有错误的参数数目,仅举几例。特别节目,叫做棉短绒(从C程序验证工具lint的名称),通常以被用来保证没有这样的错误都存在。现代Fortran编译器也试图比旧版编译器严格得多,并尽可能地检测错误。

现代Fortran版本提供了INTERFACE构造,允许显式声明函数接口,与C中的函数原型非常相似。模块子例程和函数自动生成接口并使其可用于模块的调用方。当调用具有显式接口子程序/函数,编译器能够验证电话的有效性,即它检查的参数和它们的类型的数量相匹配的接口中。

您应该为外部例程提供一个接口,然后编译器将能够执行检查。人们通常使用ISO_C_BINDING方法以接口为C代码:

INTERFACE 
    SUBROUTINE test(x, y, z) BIND(C, NAME="test") 
    USE, INTRINSIC :: ISO_C_BINDING 
    REAL(KIND=C_DOUBLE), INTENT(...) :: x ! Put the proper intents 
    REAL(KIND=C_DOUBLE), INTENT(...) :: y 
    REAL(KIND=C_DOUBLE), INTENT(...) :: z 
    END SUBROUTINE test 
END INTERFACE 

有了这个接口,CALL test(x, y)会导致编译时错误,因为参数数量不匹配的。

+0

@_Hristo谢谢你。我会尝试的。学习新东西总是健康的。 – Manolete