Фортран многомерных массивов фиксированного размера в интероперабельных производных типах - PullRequest
0 голосов
/ 15 мая 2018

У меня есть библиотека Фортрана, для которой я пытаюсь создать привязки Си.Библиотека Фортрана использует многомерные массивы фиксированного размера, содержащиеся в производных типах.(Изначально это были глобальные переменные в унаследованном коде 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

Когда я запускаю это, я получаю segfault в set_structs для i = 1, j =103. Однако, если я закомментирую все ссылки на iarray, он будет работать нормально.Таким образом, проблема возникает только в том случае, если в производном типе Фортрана имеется более 1 многомерного массива.Один многомерный массив работает нормально (struct_a с закомментированным iarray), а несколько одномерных массивов работают нормально (struct_b).Я также тестировал без производных типов, просто передавая четыре массива в Fortran из C (два 2-мерных и 2 1-мерных), и это тоже отлично работает.Я как бы в своем уме, поэтому я очень ценю несколько советов о том, как сделать это правильно.

РЕДАКТИРОВАТЬ: как отмечено francescalus в комментарии ниже, проблема с этим примером просточто я пытаюсь получить доступ к элементам iarray, выходящим за границы, так что это не хороший пример реальной проблемы с моим кодом.См. Принятый ответ для фактической причины и решения.

1 Ответ

0 голосов
/ 16 мая 2018

Я выяснил проблему в своем реальном коде, на случай, если кому-то будет интересно. Похоже, что с #defines в заголовочном файле. Например, у меня были такие заявления, как:

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

Очевидно, что это не работает, что, возможно, я бы знал, если бы я был более знаком с препроцессором Си. Вместо этого сделайте это:

#define IQX 360
#define IWX 47
#define IZX 407
...