Home > Archive > Fortran > March 2008 > Re: how can I use C allocated memory in fortran ?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Re: how can I use C allocated memory in fortran ?
|
|
|
| On 21 mar, 08:31, zhaoping...@gmail.com wrote:
> I must use the C allocated memory in FORTRAN ,I suppose the following
> code can work ,but I failed
>
> //c code----------------------------
> void get_in_(int **x)
> {
> *x=(int *)malloc(sizeof(int)*10);
> }
>
> !fortran code ///////////////////////////////////////////////
> program memtest
> integer ,pointer :: p(:)
> get_in(p) !I get segment fault here
> end
>
> GCC /GFORTRAN ON LINUX FC6
>
> In my project , fortran code want get data form the C code , the C
> code get POSIX shared memory and return to fortran , how could I do
> this ?
In using the F2003 iso_c_binding module as follow :
void get_in(int *x,int n){
x=(int *)malloc(sizeof(int)*n);
}
PROGRAM memtest
USE iso_c_binding
INTERFACE
SUBROUTINE get_in(x,n) BIND(C,name="get_in")
USE iso_c_binding
TYPE(C_PTR) ,VALUE :: x
INTEGER(C_INT),VALUE :: n
END SUBROUTINE
END INTERFACE
TYPE(C_PTR) :: px
INTEGER,POINTER :: x(:)
INTEGER :: n=10 ! here the FORTRAN side decides the
size of the array
CALL get_in(px,n) ! C allocation
CALL C_F_POINTER(px,x,(/n/)) ! transforming px into x
... ! normal use of x here
END PROGRAM
Notice that the C routine has been slightly modified too :
- no final underscore (not necessary because of BIND(c,name="get_in")
which avoids extra FORTRAN decoration
- the dimension of the array is passed as input argument (it could be
also an output argument in declaring it *int on the C side, in
initializing it from the C side, and in deleting the VALUE keyword
from the FORTRAN side)
| |
| James Van Buskirk 2008-03-21, 7:20 pm |
| "fj" <francois.jacq@irsn.fr> wrote in message
news:a127a63f-2268-4643-97ac-a81c38a87ae6@o22g2000hsh.googlegroups.com...
> void get_in(int *x,int n){
> x=(int *)malloc(sizeof(int)*n);
> }
> PROGRAM memtest
> USE iso_c_binding
> INTERFACE
> SUBROUTINE get_in(x,n) BIND(C,name="get_in")
> USE iso_c_binding
> TYPE(C_PTR) ,VALUE :: x
> INTEGER(C_INT),VALUE :: n
> END SUBROUTINE
> END INTERFACE
> TYPE(C_PTR) :: px
> INTEGER,POINTER :: x(:)
> INTEGER :: n=10 ! here the FORTRAN side decides the
> size of the array
> CALL get_in(px,n) ! C allocation
> CALL C_F_POINTER(px,x,(/n/)) ! transforming px into x
> ... ! normal use of x here
> END PROGRAM
Good response, except...
If x is passed as a C_PTR by value, the C function will attempt to
dereference the pointer, and you haven't pointed it at anything in
your Fortran program. If you still insist on passing x as a C_PTR
by value, then you must point it at something:
TYPE(C_PTR), TARGET :: tx
...
px = C_LOC(tx)
...
CALL C_F_POINTER(tx,x,[n])
Now get_in() will point tx at what malloc() allocated. Hmm... you
also have changed get_in() in an unfortunate way: you changed the
declaration of x from pointer to pointer to int to simply pointer
to int. If you do that, get_in() gets a local copy of a pointer,
allocates memory, points the local copy of the pointer at the
memory, then returns without changing the caller's version of the
pointer that points at the allocated memory. So I am assuming that
you will want to change get_in() back to its original version. You
may then wish to change the declaration of dummy argument x to:
TYPE(C_PTR) :: x
If you do so then there will be no need to do that messy stuff with
tx in your main program and it should be OK except for that single
modification. It's tricky to get the levels of indirection right
here, but I think I have done so.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
| |
| James Van Buskirk 2008-03-21, 7:20 pm |
| "James Van Buskirk" <not_valid@comcast.net> wrote in message
news:PdydnQhsrsRMKX7anZ2dnUVZ_r-vnZ2d@comcast.com...
> It's tricky to get the levels of indirection right
> here, but I think I have done so.
Well, I had to test to be sure that I got it right. Here are tests
of both of my recommended methods:
C:\gfortran\clf\malloc_test>type malloc_test1.f90
subroutine get_in(x, n) bind(C,name='get_in')
use ISO_C_BINDING
implicit none
type(C_PTR), value :: x
integer(C_SIZE_T), value :: n
type(C_PTR), pointer :: rx
interface
function malloc(n) bind(C,name='malloc')
use ISO_C_BINDING
implicit none
type(C_PTR) malloc
integer(C_SIZE_T), value :: n
end function malloc
end interface
integer(C_SIZE_T) i
integer(C_INT), pointer :: tx(:)
call C_F_POINTER(x, rx)
rx = malloc(size(transfer(0_C_INT, [0_C_INT8_T]))*n)
call C_F_POINTER(rx, tx, [n])
tx = [(i,i=1,n)]
end subroutine get_in
program memtest
use ISO_C_BINDING
implicit none
interface
subroutine get_in(x, n) bind(C,name='get_in')
use ISO_C_BINDING
implicit none
type(C_PTR), value :: x
integer(C_SIZE_T), value :: n
end subroutine get_in
end interface
type(C_PTR) px
integer(C_INT), pointer :: x(:)
integer(C_SIZE_T) n
type(C_PTR), target :: tx
n = 10
px = C_LOC(tx)
call get_in(px, n)
call C_F_POINTER(tx, x, [n])
write(*,*) x
end program memtest
C:\gfortran\clf\malloc_test>C:\gcc_equation\bin\x86_64-pc-mingw32-gfortran
mallo
c_test1.f90 -omalloc_test1
C:\gfortran\clf\malloc_test>malloc_test1
1 2 3 4 5 6
7 8 9 10
C:\gfortran\clf\malloc_test>type malloc_test2.f90
subroutine get_in(x, n) bind(C,name='get_in')
use ISO_C_BINDING
implicit none
type(C_PTR), value :: x
integer(C_SIZE_T), value :: n
type(C_PTR), pointer :: rx
interface
function malloc(n) bind(C,name='malloc')
use ISO_C_BINDING
implicit none
type(C_PTR) malloc
integer(C_SIZE_T), value :: n
end function malloc
end interface
integer(C_SIZE_T) i
integer(C_INT), pointer :: tx(:)
call C_F_POINTER(x, rx)
rx = malloc(size(transfer(0_C_INT, [0_C_INT8_T]))*n)
call C_F_POINTER(rx, tx, [n])
tx = [(i,i=1,n)]
end subroutine get_in
program memtest
use ISO_C_BINDING
implicit none
interface
subroutine get_in(x, n) bind(C,name='get_in')
use ISO_C_BINDING
implicit none
type(C_PTR) :: x
integer(C_SIZE_T), value :: n
end subroutine get_in
end interface
type(C_PTR) px
integer(C_INT), pointer :: x(:)
integer(C_SIZE_T) n
n = 10
call get_in(px, n)
call C_F_POINTER(px, x, [n])
write(*,*) x
end program memtest
C:\gfortran\clf\malloc_test>C:\gcc_equation\bin\x86_64-pc-mingw32-gfortran
mallo
c_test2.f90 -omalloc_test2
C:\gfortran\clf\malloc_test>malloc_test2
1 2 3 4 5 6
7 8 9 10
Sweet success!
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
| |
| glen herrmannsfeldt 2008-03-21, 7:20 pm |
| James Van Buskirk wrote:
(snip)
> Well, I had to test to be sure that I got it right. Here are tests
> of both of my recommended methods:
> C:\gfortran\clf\malloc_test>type malloc_test1.f90
> subroutine get_in(x, n) bind(C,name='get_in')
> use ISO_C_BINDING
> implicit none
> type(C_PTR), value :: x
> integer(C_SIZE_T), value :: n
> type(C_PTR), pointer :: rx
> interface
> function malloc(n) bind(C,name='malloc')
> use ISO_C_BINDING
> implicit none
> type(C_PTR) malloc
> integer(C_SIZE_T), value :: n
> end function malloc
> end interface
> integer(C_SIZE_T) i
> integer(C_INT), pointer :: tx(:)
>
> call C_F_POINTER(x, rx)
> rx = malloc(size(transfer(0_C_INT, [0_C_INT8_T]))*n)
> call C_F_POINTER(rx, tx, [n])
> tx = [(i,i=1,n)]
> end subroutine get_in
(snip)
I thought get_in() was supposed to be a C function, though by
calling malloc() it still satisfies the requirement of
C allocated memory.
You could continue, though, and write a malloc() in Fortran that
ALLOCATEs the memory and returns the C_LOC() of it.
Otherwise, my choice might have been to do all the allocation
in Fortran, even for C routines.
-- glen
|
|
|
|
|