Попытка обработать указатель на Фортране - вызвать c_f_pointer - PullRequest
0 голосов
/ 16 мая 2018

У меня проблема при попытке обработать указатель на Фортран после использования: call c_f_pointer(dataPtr, dataF, [natoms,countf]), где dataPtr - указатель C с intent(in), а dataF - указатель Фортрана с intent(out).

natoms и countf - целые числа, определяющие размер выходного указателя.

Переменные были ранее объявлены как:

use, intrinsic :: iso_c_binding
integer natoms, countf
type(c_ptr) dataPtr
real(c_float), pointer :: dataF(:,:) => NULL()

и dataPtr происходят из другой функции.

Если я напечатаю shape(dataF), я получу правильный результат. Но я не могу печатать или копировать или делать что-либо с dataF. Я получаю ошибку forrtl: серьезная (174): SIGSEGV, произошла ошибка сегментации .

Я последовал примеру https://software.intel.com/en-us/node/678433,, который я могу без проблем компилировать и манипулировать.


РЕДАКТИРОВАТЬ: добавить больше кода.

program test

use, intrinsic :: iso_c_binding
implicit none

interface
    subroutine open(ptr) bind(c, name='open')
        use, intrinsic :: iso_c_binding
        implicit none
        type(c_ptr), intent(out) :: ptr
    end subroutine open
    subroutine gather(ptr, name, typ, countf, data) bind(c, name='gather')
        use, intrinsic :: iso_c_binding
        implicit none
        type(c_ptr), value, intent(in) :: ptr
        type(c_ptr), value, intent(in) :: name
        integer(c_int), value, intent(in) :: typ
        integer(c_int), value, intent(in) :: countf
        type(c_ptr), intent(out) :: data
    end subroutine gather
    subroutine scatter(ptr, name, typ, countf, data) bind(c, name='scatter')
        use, intrinsic :: iso_c_binding
        implicit none
        type(c_ptr), value, intent(in) :: ptr
        type(c_ptr), value, intent(in) :: name
        integer(c_int), value, intent(in) :: typ
        integer(c_int), value, intent(in) :: countf
        type(c_ptr), intent(in) :: data
    end subroutine scatter
end interface

integer natoms, countf, typ
character(len=2,kind=c_char) :: var = c_char_'x'//c_null_char
type(c_ptr) ptr, dataPtr
real(c_float), pointer :: dataF(:,:) => NULL()

!opens an instance of the program (loaded as library into my Fortran)
!ptr is a pointer used to reference to it in other calls
call open(ptr)

!Here comes definitions for the integer variables
!...

!get data
call gather(ptr, c_loc(var), typ, countf, dataPtr)

!need to do stuff with the data here
call c_f_pointer(dataPtr, dataF, [natoms,countf])

!return modified data
call scatter(ptr, c_loc(var), typ, countf, dataPtr)

Если я просто получу данные call gather(...), а затем верну их call scatter(...), программа работает. Но мне нужно сделать что-то промежуточное.


EDIT2: добавлены функции C

void open(void **ptr) {
// ...
}

void gather(void *ptr, const char *name,
                     int type, int count, void *data) {
// ...
}

void scatter(void *ptr, const char *name,
                     int type, int count, void *data) {
// ...
}

1 Ответ

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

Видимо я понял.

Прежде всего указатель данных должен вводиться как intent(in) и value в подпрограмме gather:

subroutine gather(ptr, name, typ, countf, data) bind(c, name='gather')
    ! ...
    type(c_ptr), value, intent(in) :: data
    ! instead of:
    ! type(c_ptr), intent(out) :: data
end subroutine gather

и я изменил объявление dataF, которое больше не нужно вызывать с c_f_pointer:

real(c_float), target, allocatable :: dataF(:,:)

Поэтому я удалил call c_f_pointer(dataPtr, dataF, [natoms,countf]) и добавил вместо:

allocate(dataF(natoms,countf))
dataPtr = c_loc(dataCFloat)

Теперь dataF содержит обновленный массив напрямую.

...