【问题标题】:gfortran -fc-prototypes option for function pointers函数指针的 gfortran -fc-prototypes 选项
【发布时间】:2020-10-22 18:30:03
【问题描述】:

gfortran 编译器具有interoperability option -fc-prototypes,它为可互操作的函数(具有 BIND(C) 属性)生成正确的 C 原型。

在链接中写道:“对于函数指针,会生成一个指向返回 int 且没有显式参数列表的函数的指针。”

我尝试了一些包含 BIND(C) 子例程的代码,该子例程将函数指针指向具有 2 个整数参数的子例程。取文件test.F95中的Fortran代码:

subroutine test(pf) bind(c)

    use, intrinsic :: iso_c_binding
    implicit none
    type(c_funptr), intent(in), value :: pf
    
    abstract interface
        subroutine fproto(x, y) bind(c)
            use iso_c_binding, only: c_int
            integer(c_int), intent(in), value :: x, y
        end subroutine fproto
    end interface
    procedure(fproto), pointer :: f

    call c_f_procpointer(pf, f)
    call f(1, 2)
end subroutine test

编译:gfortran test.F95 -c -Wall -fc-prototypes > proto.h

这会生成 C 头文件proto.h,内容如下:

#include <stddef.h>
#ifdef __cplusplus
#include <complex>
#define __GFORTRAN_FLOAT_COMPLEX std::complex<float>
#define __GFORTRAN_DOUBLE_COMPLEX std::complex<double>
#define __GFORTRAN_LONG_DOUBLE_COMPLEX std::complex<long double>
extern "C" {
#else
#define __GFORTRAN_FLOAT_COMPLEX float _Complex
#define __GFORTRAN_DOUBLE_COMPLEX double _Complex
#define __GFORTRAN_LONG_DOUBLE_COMPLEX long double _Complex
#endif

void f ();
void fproto (int x, int y);
void test (int (*pf)());

#ifdef __cplusplus
}
#endif

如您所见,抽象接口中的子程序fproto的原型是正确的。但是 test 子程序的参数的正确 C 原型,即函数指针应该是:

void (*pf)(int, int)

但是 gfortran 生成

int (*pf)()

这根本不匹配。这有什么意义?这是否意味着我应该始终将函数指针传递给返回 int 的函数?还是这只是(故意?)产生的错误?

【问题讨论】:

  • 需要看一些实际代码。
  • @evets 我添加了一些代码。
  • 虚拟参数pf 的类型是c_funptr:你为什么希望gfortran 生成void (*pf)(int, int)?
  • @francescalus 因为在 C 端,我必须将指向 void (*)(int, int) 类型的函数而不是 int(*)() 类型的函数的指针传递给 test 函数。生成错误的 C 接口有什么意义?还是 Fortran 代码不正确,我应该使用不同于 c_funptr 的东西?但是它编译时没有任何警告。
  • 如果你没有那个c_f_procptr 调用,或者它被使用了两次不同的原型(有条件地,可能),或者它是一个隐式接口怎么办?也就是说,gfortran 不能涵盖所有情况,所以它必须选择一些东西。 (你现在有一个涵盖这个的答案,所以最好在那里继续进一步讨论。)

标签: c fortran function-pointers gfortran fortran-iso-c-binding


【解决方案1】:

gfortran 正在按设计和记录(在第二段的问题中实际引用的相关文档!)here。

子例程测试将通用 C 函数指针作为参数。从该子例程接口的互操作性来看,可以传入任何函数。gfortran 对任何函数的匹配函数的解释是“指向函数的指针,返回 int 而没有显式参数列表”。

Fortran 过程指针与函数指针的关联是一种执行时间活动。原型描述了函数的特性,是一个编译时的概念。

【讨论】:

  • 好的,谢谢,所以在使用之前我总是必须手动更正它。但是过程指针f 呢? gfortran 不应该在编译时知道这是fproto 类型,因此生成正确的C 函数原型,即void f(int, int)?为什么void f()?
  • 我不知道。我怀疑编译器只是对那个感到困惑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多