C + Fortran为什么sigsegv?

时间:2012-12-14 15:01:35

标签: c interop fortran fortran2003 fortran-iso-c-binding

我在Fortran中使用以下代码并使用C“master”。它给了sigsegv,但我不明白为什么。它应该从主C程序中取一个指针将其转换为Fortran指针格式,并读出指向的数据C指针。什么都不花哨,但仍然是SigSegv。这是BTW唯一可以避免Fortran多维数组缺乏互操作性的方法......(是的,C没有多维数组)。

Fortran部分:

module ret
    implicit none
    integer, pointer :: a(:,:)
end module ret

module func
    implicit none
    contains

    subroutine initialize(cp) bind(c,name='initialize')
        use ret
        use iso_c_binding
        implicit none
        type(c_ptr) :: cp

        call c_f_pointer(cp,a,[5,5])

    end subroutine initialize

    subroutine printa bind(c,name='printa')
       use ret
       implicit none
       integer :: i,j

       do i=1,5
         do j=1,5
            print *,i,j,a(i,j)
         end do
       end do
    end subroutine printa
end module func

C部分:

#include<stdio.h>
void initialize( void *);
void printa();

int main()
 {    
  int *tab;
  tab = (int *)malloc(25 * sizeof (int *));
  int i;
  for(i=0;i<25;++i)
   tab[i]=i;
  initialize(tab);
  printa();
  printf("ok\n");
  return 0;
 }

SIGSEGV发生在Fortran部分的print *,i,j,a(i,j)

编辑: 我已将“integer * 8”更改回“整数” 并do i=1,10返回do i=1,5。对于这个版本,问题仍然有效

SIGSEGV出现i = 1,j = 1

1 个答案:

答案 0 :(得分:3)

我将此作为答案添加,以防其他人来这里遇到问题,与您的问题类似。

显示的代码有两个问题。首先,您正在为整数指针分配内存,如KlasLindbäck所述。这是问题的根源,因为指针的大小至少是int或更宽,但是应该向sizeof运算符提供正确的数据类型为了防止过度使用可用资源。

第二个问题是Fortran参数是通过引用传递的。这意味着当从C调用Fortran例程时,应使用 address-of 运算符&。常量也应该放在单独的常量变量中,并且也要通过地址传递。纠正上一个问题后,C代码应为:

tab = malloc(25 * sizeof (int)); // int instead of int *
int i;
for(i = 0; i < 25; ++i)
  tab[i] = i;
initialize(&tab);                // pass tab by address

Fortran 2003引入了VALUE属性,该属性可以应用于虚拟例程参数,以便使它们按值传递。如果您的Fortran编译器实现了此F2003功能,那么您可以将cp的{​​{1}}伪参数的声明更改为:

initialize

如果您这样做,则无需通过引用传递type(c_ptr), value :: cp