Как выделить массив внутри фортрановой подпрограммы, "вызываемой" из C - PullRequest
4 голосов
/ 13 марта 2012

Я думаю, что название говорит, что мне нужно.Я знаю, что мы можем использовать функцию «asd» для этого, но по некоторым причинам мне нужно сделать выделение в Fortran (то есть в подпрограмме «asd_»).Вот код C:

#include <stdio.h>

void asd(float **c) {
  *c = (float *) malloc (2*sizeof(float));
  **c =123;
  *(*c+1)=1234;
}

void asd_(float **c);

main () {
  float *c;
  asd_(&c);
// asd(&c); would do the job perfectly
  printf("%f %f \n",c[0],c[1]);
  return 0;
}

А вот код Фортрана:

  subroutine asd(c)

  implicit none

  real, pointer, allocatable ::c(:)

  print *, associated(c)
  if(.not. associated(c))  allocate(c(2))

  end subroutine 

Это случайным образом дает ошибку сегментации.Любая помощь будет оценена.

Ответы [ 3 ]

10 голосов
/ 13 марта 2012

Связывание Fortran 2003 ISO C обеспечивает переносимый способ сделать это. Это реализовано во многих компиляторах. Вот пример кода.

#include <stdio.h>

void test_mem_alloc ( float ** array );

int main ( void ) {

   float * array;
   test_mem_alloc (&array);

   printf ( "Values are: %f %f\n", array [0], array [1] );

   return 0;
}

и

subroutine test_mem_alloc ( c_array_ptr ) bind (C, name="test_mem_alloc")

   use, intrinsic :: iso_c_binding
   implicit none

   type (c_ptr), intent (out) :: c_array_ptr
   real (c_float), allocatable, dimension (:), target, save :: FortArray

   allocate (FortArray (1:2) )
   FortArray = [ 2.5_c_float, 4.4_c_float ]

   c_array_ptr = c_loc (FortArray)

end subroutine test_mem_alloc
1 голос
/ 01 июля 2016

Если вам нужно поточно-ориентированное решение и / или возможность снова освободить пространство из C, приведенный ниже пример сделает эту работу:

#include <stdio.h>

void test_mem_alloc(float ** array, void **wrapper);
void free_wrapper(void **wrapper);

int main()
{

  float *array;
  void *wrapper;

  /* Allocates space in Fortran. */
  test_mem_alloc(&array, &wrapper);
  printf( "Values are: %f %f\n", array [0], array [1]);
  /* Deallocates space allocated in Fortran */
  free_wrapper(&wrapper);

  return 0;
}

На стороне Fortran у вас есть общая оболочкатип CWrapper, который может нести любой тип производного типа.Последние содержат данные, которые вы хотели бы передать.Тип CWrapper принимает произвольную полезную нагрузку, и вы всегда вызываете подпрограмму free_wrapper() из C для освобождения памяти.

module memalloc
  use, intrinsic :: iso_c_binding
  implicit none

  type :: CWrapper
    class(*), allocatable :: data
  end type CWrapper

  type :: CfloatArray
    real(c_float), allocatable :: array(:)
  end type CfloatArray

contains

  subroutine test_mem_alloc(c_array_ptr, wrapper_ptr)&
      & bind(C, name="test_mem_alloc")
    type (c_ptr), intent (out) :: c_array_ptr
    type(c_ptr), intent(out) :: wrapper_ptr

    type(CWrapper), pointer :: wrapper

    allocate(wrapper)
    allocate(CfloatArray :: wrapper%data)
    select type (data => wrapper%data)
    type is (CfloatArray)
      allocate(data%array(2))
      data%array(:) = [2.5_c_float, 4.4_c_float]
      c_array_ptr = c_loc(data%array)
    end select
    wrapper_ptr = c_loc(wrapper)

  end subroutine test_mem_alloc


  subroutine free_cwrapper(wrapper_ptr) bind(C, name='free_wrapper')
    type(c_ptr), intent(inout) :: wrapper_ptr

    type(CWrapper), pointer :: wrapper

    call c_f_pointer(wrapper_ptr, wrapper)
    deallocate(wrapper)

  end subroutine free_cwrapper

end module memalloc
1 голос
/ 14 марта 2012

Вот еще одно решение, если вы хотите использовать встроенные типы Fortran. Это был мой случай, так как мне нужно было вызывать подпрограммы из внешней библиотеки, используя предварительно определенные типы данных. Это в основном делается с помощью программы-оболочки Fortran. Вот код C:

void mywrap_(void **);
void myprint_(void *);

main () {
  void *d;
  mywrap_(&d);
  myprint_(d);
  return 0;
}

А вот и оболочка:

  subroutine mywrap(b)
  implicit none
  include "h.h"     
  type(st), target, save :: a
  integer, pointer :: b
  interface 
     subroutine alloc(a)
        include "h.h"
        type(st) a
     end subroutine alloc
  end interface

  call alloc(a)
  b => a%i
  end

И коды Фортрана:

  subroutine alloc(a)
  implicit none 
  include "h.h"
  type(st) a

  a%i = 2
  a%r = 1.5
  if (allocated(a%s)) deallocate(a%s)
  allocate(a%s(2))
  a%s(1) = 1.23
  a%s(2) = 1234
  end
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  subroutine myprint(a)
  implicit none
  include "h.h"     
  type(st) a

  print *,"INT: ", a%i
  print *,"REAL: ", a%r
  print *,"ALLOC: ", a%s
  end

И заголовочный файл "h.h":

  type st
     sequence
     integer i
     real r
     real, allocatable :: s(:)
  end type

Обратите внимание, что таким образом все объекты непрозрачны в C.

...