Хорошо, я собираюсь предположить, что двоеточия имеют какое-то отношение к строкам продолжения, и игнорировать их, и вы пытаетесь это сделать:
do i = 0, 5
CALL C_F_POINTER(&
TRANSFER(memory_location + VarNamesLoc_(i), memory_location_cptr), &
VarNames_(i), [3] )
enddo
То, что он делает, это: (ПЕРЕДАЧА) берет целое число, представляющее существующий указатель C (я предполагаю) memory_location
, добавляем к нему смещение (VarNamesLoc_(i)
) и превращаем его в тип c_ptr
. И затем (C_F_POINTER) преобразует это в указатель формы Fortran [3].
Я не думаю, что делать арифметику С-указателей на стороне Фортрана - отличная идея, но.
Итак, вы хотите, чтобы VarNames_
был массивом из 5 указателей на массивы из 3 .. чего-то, что вы не сказали. Скажем, целые числа.
Давайте возьмем это из простого случая: скажем, у нас был одномерный массив целых чисел в C, и мы хотели указатель на них в Fortran. Если бы наша подпрограмма C была такой (croutine.c
):
#include <stdio.h>
#include <stdlib.h>
void makearray(int **data, int n) {
*data = (int *)malloc(n * sizeof(int));
for (int i=0; i<n; i++)
(*data)[i] = i;
return;
}
void freearray(int **data, int n) {
free(*data);
return;
}
наш драйвер Fortran может выглядеть следующим образом (driver.f90):
PROGRAM interoptesting
USE, intrinsic :: iso_c_binding
USE, intrinsic :: iso_fortran_env
IMPLICIT NONE
INTERFACE
!! C prototype: void makearray(int **data, int n)
SUBROUTINE makearray(data, n) BIND(C)
USE, intrinsic :: iso_c_binding
type(c_ptr) :: data
integer(kind=c_int), value :: n
END SUBROUTINE makearray
!! C prototype: void freearray(int **data, int n)
SUBROUTINE freearray(data, n) BIND(C)
USE, intrinsic :: iso_c_binding
type(c_ptr) :: data
integer(kind=c_int), value :: n
END SUBROUTINE freearray
END INTERFACE
type(c_ptr) :: cdata
integer, pointer, dimension(:) :: fdata
integer :: n = 5
call makearray(cdata, n);
call c_f_pointer(cdata, fdata, [n])
print *, 'fdata = ', fdata
call freearray(cdata, n)
END program
и Makefile вроде этого:
FC=gfortran
CC=gcc
CFLAGS=-std=c99 -g
FFLAGS=-g
main: driver.o croutine.o
$(FC) -o $@ $^
driver.o: driver.f90
$(FC) $(FFLAGS) -c $<
clean:
rm -rf main driver.o croutine.o
и, собрав его и запустив, мы получим ожидаемый ответ:
$ ./main
fdata = 0 1 2 3 4
Обратите внимание, что в C мы выделили массив из 5-ти дюймов; Программа Fortran в основном определяет интерфейс для подпрограмм C, поэтому мы можем вызывать их из Fortran, а затем вызывать их. c_f_pointer
выполняет перевод между указателем c (cdata
) и указателем Fortran (fdata
).
Если мы хотим сделать некоторую арифметику с C-указателем в Fortran, мы можем сделать это:
type(c_ptr) :: cdata, newdata
integer(kind=int64) :: tmpint
integer, pointer, dimension(:) :: fdata
integer :: n = 5
integer(kind=c_int) :: cint
call makearray(cdata, n);
! copy pointer to an int
tmpint = TRANSFER(cdata, tmpint)
! add two integer sizes:
tmpint = tmpint + 2*c_sizeof(cint)
! copy back into a pointer
newdata= TRANSFER(tmpint, newdata)
call c_f_pointer(newdata, fdata, [n-2])
print *, 'fdata = ', fdata
call freearray(cdata, n)
Но я действительно не рекомендовал бы это; лучше сделать манипуляции с указателем в Фортране:
type(c_ptr) :: cdata
integer, pointer, dimension(:) :: fdata, newfdata
integer :: n = 5
call makearray(cdata, n);
call c_f_pointer(cdata, fdata, [n])
newfdata => fdata(3:n)
print *, 'newfdata = ', newfdata
call freearray(cdata, n)
Более чистый, менее вероятный, чтобы вызвать странные ошибки, и меньший, также!
Хорошо, наконец, давайте сделаем массив указателей. По общему признанию, это сложнее, чем должно быть в Фортране, потому что Фортран нелегко позволяет вам определять массивы указателей; Вы должны создать определенный тип (Fortran-эквивалент структуры в C). Но это достаточно просто. Давайте сделаем то, что я рекомендую, выполняя указатель по математике на стороне Фортрана:
type(c_ptr) :: cdata
integer, pointer, dimension(:) :: fdata
integer :: n = 10
integer, parameter :: nptrs = 5
integer :: i, intsperptr, istart, iend
! our new "ptrelement" type which we can define arrays of
type ptrelement
integer, pointer, dimension(:) :: p
end type ptrelement
type(ptrelement) :: ptrs(nptrs)
call makearray(cdata, n);
call c_f_pointer(cdata, fdata, [n])
intsperptr = n/nptrs
do i=1,nptrs
istart = (i-1)*intsperptr+1
iend = istart + intsperptr-1
ptrs(i)%p => fdata(istart:iend)
enddo
do i=1,nptrs
print '(A,I2,A,99(I5,X))', 'ptrs(',i,')%p = ', ptrs(i)%p
enddo
call freearray(cdata, n)
Здесь мы создали тип ptrelelment
, который является массивом 1-d указателей, а затем создали их массив. Это дает нам наш массив указателей, который мы устанавливаем, взяв кусочки fdata
, которые по-прежнему являются указателем на все данные.
бег дает нам
$ ./main
ptrs( 1)%p = 0 1
ptrs( 2)%p = 2 3
ptrs( 3)%p = 4 5
ptrs( 4)%p = 6 7
ptrs( 5)%p = 8 9
Или, как я не предлагаю, сделать математику указателя в стиле C на Фортране:
type(c_ptr) :: cdata
integer :: n = 10
integer, parameter :: nptrs = 5
integer :: i, intsperptr
integer(kind=c_int) :: cint
integer(kind=int64) :: cdata_as_int
! our new "ptrelement" type which we can define arrays of
type ptrelement
integer, pointer, dimension(:) :: p
end type ptrelement
type(ptrelement) :: ptrs(nptrs)
call makearray(cdata, n);
cdata_as_int = TRANSFER(cdata, cdata_as_int)
intsperptr = n/nptrs
do i=1,nptrs
call c_f_pointer( &
TRANSFER(cdata_as_int + (i-1)*intsperptr*c_sizeof(cint), cdata),&
ptrs(i)%p, [intsperptr] )
enddo
do i=1,nptrs
print '(A,I2,A,99(I5,X))', 'ptrs(',i,')%p = ', ptrs(i)%p
enddo
call freearray(cdata, n)