可互操作的派生类型中的Fortran固定大小多维数组

时间:2018-05-15 15:32:18

标签: arrays multidimensional-array fortran interop

我有一个Fortran库,我正在尝试为其创建C绑定。 Fortran库使用派生类型中包含的固定大小的多维数组。 (这些最初是传统Fortran代码中的全局变量;我将所有全局变量放在派生类型中以用于封装。)如果我使用此库在Fortran中创建测试用例,在这种情况下,派生类型将被初始化在Fortran代码中,一切都很顺利,但是当我在C中尝试相同时,在这种情况下派生类型在C中作为结构初始化,我得到了一个分段错误。

这是一个显示问题的最小示例。 Fortran库还使用包含其他派生类型的分组派生类型,因此我在示例中包含了该类型。

testmod.f90:

module testmod

  use iso_c_binding

  implicit none

  integer(c_int), parameter :: RSIZE1 = 360
  integer(c_int), parameter :: RSIZE2 = RSIZE1/2
  integer(c_int), parameter :: ISIZE1 = RSIZE1
  integer(c_int), parameter :: ISIZE2 = ISIZE1/4

  type, bind(c) :: struct_a
    real(c_double) :: rarray(RSIZE1,RSIZE2)
    integer(c_int) :: iarray(ISIZE1,ISIZE2)
  end type struct_a

  type, bind(c) :: struct_b
    real(c_double) :: rvec(RSIZE1)
    integer(c_int) :: ivec(ISIZE1)
  end type struct_b

  type, bind(c) :: struct_group
    type(struct_a) :: a
    type(struct_b) :: b
  end type struct_group

  contains

subroutine set_structs(group) bind(c, name="set_structs")

  type(struct_group), intent(inout) :: group
  integer i, j

  do i = 1, RSIZE1
    group%b%rvec(i) = dble(i)
    group%b%ivec(i) = i 
    do j = 1, RSIZE2
      group%a%rarray(i,j) = dble(i*j)
      group%a%iarray(i,j) = i*j
      write(*,*) "Here", i, j
    end do
  end do

end subroutine set_structs

end module testmod

test.h:

#pragma once

#define RSIZE1 360
#define RSIZE2 RSIZE1/2
#define ISIZE1 RSIZE1
#define ISIZE2 ISIZE1/4

typedef struct
{ 
  double rarray[RSIZE1*RSIZE2];
  int iarray[ISIZE1*ISIZE2];
} struct_a;

typedef struct
{ 
  double rvec[RSIZE1];
  int ivec[ISIZE1];
} struct_b;

typedef struct
{
  struct_a a;
  struct_b b;
} struct_group;

extern void set_structs(struct_group *group);

test.c的:

#include "test.h"

int main()
{
  struct_group group;
  set_structs(&group);
  return 0;
} 

编译如下:

gfortran -c -fPIC -Wall testmod.f90
gcc -c -fPIC -Wall test.c
gfortran -o test testmod.o test.o

当我运行这个时,我在set_structs中得到一个段错误,i = 1,j = 103.但是,如果我注释掉所有对iarray的引用,它就可以了。因此,只有当Fortran派生类型中存在多个多维数组时,才会出现此问题。单个多维数组工作正常(struct_a with iarray注释掉),多个1维数组工作正常(struct_b)。我还测试了没有派生类型,只是从C传递四个数组到Fortran(两个2维和2个1维),这也很好。我很有智慧在这里结束,所以我非常感谢你们如何正确地做到这一点。

编辑:正如francescalus在下面的评论中所指出的,这个例子的问题很简单,我试图访问iarray的越界元素,所以它不是一个很好的例子。我的代码真正的问题。请参阅已接受的答案,了解实际原因和解决方案。

1 个答案:

答案 0 :(得分:0)

我在我的真实代码中找到了问题,万一有人想知道。它似乎与头文件中的#defines有关。例如,我有如下声明:

#include "stdafx.h"
#include <Windows.h>
#include <WinNt.h>

#define HUNDRED 100
typedef WCHAR BUFFER_SPACE[HUNDRED]; 

void Function(BUFFER_SPACE abuffer)
{
  BUFFER_SPACE anotherbuffer = { 0 };

  wprintf(L"sizeof  abuffer      : %zd\n", sizeof(abuffer));         // 8
  wprintf(L"sizeof *abuffer      : %zd\n", sizeof(*abuffer));        // 2
  wprintf(L"sizeof anotherbuffer : %zd\n", sizeof(anotherbuffer));   // 200

  // a highly undesirable solution is to apply sizeof to the type but, if the
  // type of the parameter changes, the programmer has to be aware that the
  // original/old type is being used in sizeof() someplace else in the
  // function/program

  wprintf(L"sizeof BUFFER_SPACE  : %zd\n", sizeof(BUFFER_SPACE));  // 200

  getchar();
}

int main()
{
  BUFFER_SPACE abuffer         = { 0 };

  WCHAR anotherbuffer[HUNDRED] = { 0 };

  wprintf(L"sizeof abuffer        : %zd\n", sizeof(abuffer));
  wprintf(L"sizeof anotherbuffer  : %zd\n", sizeof(anotherbuffer));
  wprintf(L"\n");

  Function(abuffer);

  return 0;
}

显然这不起作用,如果我更熟悉C预处理器,也许我会知道。相反,这样做:

#define IQX 360
#define IWX IQX/8+2
#define IZX IQX+IWX