我从FORTRAN 90代码调用C例程.一切正常,但我想知道为什么以及如何用较少的参数调用C例程,我应该编译器不要抱怨.编译器在这做什么?我正在使用Cray编译器.
test.c的
extern "C" void test_(double* x, double* y, double* z){
// do some work
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
在函数调用方面,Fortran与C有很多不同.将参数传递给C例程时,编译器必须知道每个参数的类型,以便它可以生成适当的调用序列 - 将参数以正确的顺序放入堆栈并使用正确的填充或将它们放入预期的寄存器.如果在调用者之前定义了被调用者,C编译器通常会在编译代码时收集此信息.在所有其他情况下,应提供原型形式的函数声明.
在Fortran中,所有参数通常(有一些例外)通过地址传递,这意味着实际传递给被调用者的是一组内存指针.指针看起来一样 - 它们总是相同的类型,因此通过相同的方式.因此,Fortran编译器可以生成函数调用,而无需知道被调用者实际期望的参数.这大大简化了Fortran编译器,但它是无数可能错误的来源,例如调用具有错误参数类型的函数或甚至使用错误数量的参数,仅举几例.通常必须使用称为linters(来自C程序验证实用程序的名称)的特殊程序,lint以保证不存在此类错误.现代Fortran编译器也试图比旧版本更严格,并尽可能地尽可能地检测错误.
现代Fortran版本提供了INTERFACE允许显式声明函数接口的构造,非常类似于C中的函数原型.模块子例程和函数自动生成它们的接口USE并使模块的调用者可以使用它们.当使用显式接口调用子例程/函数时,编译器能够验证调用的有效性,即它检查参数的数量及其类型是否与接口中的参数相匹配.
您应该为外部例程提供一个接口,然后编译器就能够执行检查.通常使用该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
Run Code Online (Sandbox Code Playgroud)
有了这个接口,CALL test(x, y)由于参数计数不匹配会导致编译时错误.