3

我正在从 FORTRAN 90 代码中调用 C 例程。一切正常,但我想知道为什么以及如何使用更少的参数调用 C 例程,我应该编译器不会抱怨。编译器在这里做什么?我正在使用 Cray 编译器。

测试.c

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

司机.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
4

1 回答 1

8

在函数调用方面,Fortran 与 C 有很大不同。将参数传递给 C 例程时,编译器必须知道每个参数的类型,以便它可以生成适当的调用序列 - 将参数以正确的顺序和正确的填充放在堆栈中,或者将它们放在预期的寄存器。如果调用者在调用者之前定义,C 编译器通常会在编译代码时收集此信息。在所有其他情况下,应提供原型形式的函数声明。

在 Fortran 中,所有参数通常(有一些例外)通过地址传递,这意味着实际传递给被调用者的是一组内存指针。指针看起来是一样的——它们总是属于同一类型,因此以相同的方式传递。因此,Fortran 编译器可以在不知道被调用者实际期望什么参数的情况下生成函数调用。这极大地简化了 Fortran 编译器,但却是无数可能错误的来源,例如使用错误的参数类型或什至使用错误数量的参数调用函数,仅举几例。特殊程序,称为linter(来自 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

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

于 2013-07-17T16:11:30.020 回答