|
From: koentjepoppe on 19 Apr 2008 13:33 Dear all, I have a problem that can be reduced to the following situation: - mainf.f90 (see below) a Fortran function that returns an array containing n-copy's of a given double precision number. - mainc.c (see below) a C-file that would like to use this function. The problem is that it doesn't work (Bus Error on assigment of array(I) in the Fortran code). One way or another, the output argument is not available in the Fortran code. I know one solution would be to change the function into a subroutine, adding the result as an extra argument, but this would spoil the whole design of the project. So I'd like to know if anyone has an alternative way to solve this. Best Regards ps: for the sake of completeness: I'm using the latest stable gFortran, gcc 4.3 and I'm working on a Intel Mac. [1]: http://docs.sun.com/source/806-3593/11_cfort.html ---8<---- MAINF.F90 ---8<-------8<-------8<---- function repeatdouble( N, d ) result( array ) integer, intent( in ) :: N double precision, dimension( N ) :: array double precision, intent( in ) :: d print *, "repeat ", N, " times ..." print *, "double ", d, "." print *, "array :", array do I = 1,N print *, "making copy nb", i, " of ", N array(I) = d end do end function repeatdouble --->8------->8------->8------->8------->8------->8---- ---8<---- MAINC.C ---8<-------8<-------8<---- #include <stdio.h> extern void repeatdouble_( double*, int*, double* ); int main(){ double buf[9] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; double* ptr2buf = buf; double d = 3.141592654; int n = 4; int i; // make n copies of ch in sbf repeatdouble_( ptr2buf, &n, &d ); for( i=0; i<9; i++){ printf("buf[%i]=%d\n", i, buf[i]); } } --->8------->8------->8------->8------->8------->8----
From: glen herrmannsfeldt on 19 Apr 2008 16:11 koentjepoppe(a)gmail.com wrote: > I have a problem that can be reduced to the following situation: > - mainf.f90 (see below) > a Fortran function that returns an array containing > n-copy's of a given double precision number. > - mainc.c (see below) > a C-file that would like to use this function. > The problem is that it doesn't work (Bus Error on assigment of > array(I) in the Fortran code). One way or another, the output argument > is not available in the Fortran code. Since C doesn't have array valued functions, this isn't going to be easy. You can have functions returning a struct containing an array, though the array must be fixed size. > I know one solution would be to change the function into a subroutine, > adding the result as an extra argument, but this would spoil the whole > design of the project. So I'd like to know if anyone has an > alternative way to solve this. (snip) > ---8<---- MAINF.F90 ---8<-------8<-------8<---- > function repeatdouble( N, d ) result( array ) > integer, intent( in ) :: N > double precision, dimension( N ) :: array > double precision, intent( in ) :: d > > print *, "repeat ", N, " times ..." > print *, "double ", d, "." > print *, "array :", array > do I = 1,N > print *, "making copy nb", i, " of ", N > array(I) = d > end do > end function repeatdouble > ---8<---- MAINC.C ---8<-------8<-------8<---- > #include <stdio.h> > extern void repeatdouble_( double*, int*, double* ); This is for a three argument subroutine, not a two argument function. It is possible that the calling sequence is the same, but that is not standard. > int main(){ > double buf[9] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; > double* ptr2buf = buf; > double d = 3.141592654; > int n = 4; > int i; > // make n copies of ch in sbf > repeatdouble_( ptr2buf, &n, &d ); This agrees with a call to a Fortran subroutine, not a function. > for( i=0; i<9; i++){ > printf("buf[%i]=%d\n", i, buf[i]); > } > }
From: James Van Buskirk on 19 Apr 2008 17:54 <koentjepoppe(a)gmail.com> wrote in message news:80a7c031-33c1-4463-a60f-b4125c033a02(a)l64g2000hse.googlegroups.com... > I have a problem that can be reduced to the following situation: > - mainf.f90 (see below) > a Fortran function that returns an array containing > n-copy's of a given double precision number. > - mainc.c (see below) > a C-file that would like to use this function. > The problem is that it doesn't work (Bus Error on assigment of > array(I) in the Fortran code). One way or another, the output argument > is not available in the Fortran code. > I know one solution would be to change the function into a subroutine, > adding the result as an extra argument, but this would spoil the whole > design of the project. So I'd like to know if anyone has an > alternative way to solve this. > ps: for the sake of completeness: I'm using the latest stable > gFortran, gcc 4.3 and I'm working on a Intel Mac. > [1]: http://docs.sun.com/source/806-3593/11_cfort.html > ---8<---- MAINF.F90 ---8<-------8<-------8<---- > function repeatdouble( N, d ) result( array ) > integer, intent( in ) :: N > double precision, dimension( N ) :: array > double precision, intent( in ) :: d > print *, "repeat ", N, " times ..." > print *, "double ", d, "." > print *, "array :", array > do I = 1,N > print *, "making copy nb", i, " of ", N > array(I) = d > end do > end function repeatdouble > --->8------->8------->8------->8------->8------->8---- > ---8<---- MAINC.C ---8<-------8<-------8<---- > #include <stdio.h> > extern void repeatdouble_( double*, int*, double* ); > int main(){ > double buf[9] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; > double* ptr2buf = buf; > double d = 3.141592654; > int n = 4; > int i; > // make n copies of ch in sbf > repeatdouble_( ptr2buf, &n, &d ); > for( i=0; i<9; i++){ > printf("buf[%i]=%d\n", i, buf[i]); > } > } > --->8------->8------->8------->8------->8------->8---- The first argument to repeatdouble should not be the address of an array, rather that of the array descriptor. Disassembling a gfortran call to a similar function, we get something like: type, bind(C) :: descr integer(C_INTPTR_T) address integer(C_INTPTR_T) unknown1 integer(C_INTPTR_T) unknown2 integer(C_INTPTR_T) stride integer(C_INTPTR_T) unknown3 integer(C_INTPTR_T) last_element end type descr descr DD double precision, target :: buf(9) double precision d integer n buf = [(n,n=1,9)] d = 3.141592654 n = 4 DD = descr(C_LOC(buf), 0, 537, 1, 0, n-1) call repeatdouble_(descr, n, d) But you should ask the gfortran folks if they can round up some documentation about gfortran array descriptors for you. They are different in every compiler. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
From: FX on 19 Apr 2008 18:23 > But you should ask the gfortran folks if they can round up some > documentation about gfortran array descriptors for you. They are > different in every compiler. Yep, that's on the TODO list. Here's the short version (in C syntax). The descriptor for a given type (named here TYPE) is then: struct { TYPE *data; size_t offset; ssize_t dtype; descriptor_dimension dim[7]; } where descriptor_dimension is defined as typedef struct descriptor_dimension { ssize_t stride; ssize_t lbound; ssize_t ubound; } descriptor_dimension; All fields have the meaning implied by their name, and dtype is such that: * (dtype & 0x07) is the rank * (dtype >> 6) is the size of an array element The data component points to the first element in the array. The offset field is the position of the element (0, 0, ...). An element is accessed by data[offset + index0*stride0 + index1*stride1 + ...] All this information and more can be found in the big comment in the source at gcc/fortran/trans-types.c, line 949 in the current sources. -- FX
From: James Van Buskirk on 19 Apr 2008 19:14
"FX" <coudert(a)alussinan.org> wrote in message news:fudrd5$9ts$1(a)nef.ens.fr... >> But you should ask the gfortran folks if they can round up some >> documentation about gfortran array descriptors for you. They are >> different in every compiler. > Yep, that's on the TODO list. Here's the short version (in C syntax). Thanks for the documentation, FX! Since I can never seem to get all my ducks in a row on the first attempt, I tried a pure Fortran test of my initial recommendation and found some syntax errors. After fixing them up I got: C:\gfortran\clf\repeatdouble>type repeatdouble.f90 function repeatdouble( N, d ) result( array ) use iso_c_binding implicit none integer, intent( in ) :: N double precision, dimension( N ) :: array double precision, intent( in ) :: d integer I print *, "repeat ", N, " times ..." print *, "double ", d, "." print *, "array :", array do I = 1,N print *, "making copy nb", i, " of ", N array(I) = d end do end function repeatdouble C:\gfortran\clf\repeatdouble>type test3.f90 program main use ISO_C_BINDING implicit none type, bind(C) :: descr type(C_PTR) address integer(C_INTPTR_T) unknown1 integer(C_INTPTR_T) unknown2 integer(C_INTPTR_T) stride integer(C_INTPTR_T) unknown3 integer(C_INTPTR_T) last_element end type descr interface subroutine repeatdouble(DD,n,d) bind(C,name='repeatdouble_') use ISO_C_BINDING import descr implicit none type(descr) DD integer(C_INT) n real(C_DOUBLE) d end subroutine repeatdouble end interface type(descr) DD double precision, target :: buf(9) double precision d integer n buf = [(n,n=1,9)] d = 3.141592654 n = 4 DD = descr(C_LOC(buf), 0, 537, 1, 0, n-1) call repeatdouble(DD, n, d) write(*,'(9(f4.1))') buf end program main C:\gfortran\clf\repeatdouble>c:\gcc_equation\bin\x86_64-pc-mingw32-gfortran -c r epeatdouble.f90 C:\gfortran\clf\repeatdouble>c:\gcc_equation\bin\x86_64-pc-mingw32-gfortran test 3.f90 repeatdouble.o -otest3 C:\gfortran\clf\repeatdouble>test3 repeat 4 times ... double 3.1415927410125732 . array : making copy nb 1 of 4 So the test failed. I found the reason in test3.f90: C:\gfortran\clf\repeatdouble>type test3.f90 program main use ISO_C_BINDING implicit none type, bind(C) :: descr type(C_PTR) address integer(C_INTPTR_T) unknown1 integer(C_INTPTR_T) unknown2 integer(C_INTPTR_T) stride integer(C_INTPTR_T) unknown3 integer(C_INTPTR_T) last_element end type descr interface subroutine repeatdouble(DD,n,d) bind(C,name='repeatdouble_') use ISO_C_BINDING import descr implicit none type(descr) DD integer(C_INT) n real(C_DOUBLE) d end subroutine repeatdouble end interface type(descr) DD double precision, target :: buf(9) double precision d integer n buf = [(n,n=1,9)] d = 3.141592654 n = 4 DD = descr(C_LOC(buf), 0, 537, 1, 0, n-1) ! Shows the error: start write(*,*) DD write(*,*) C_LOC(buf) DD%address = C_LOC(buf) write(*,*) DD ! Shows the error: end call repeatdouble(DD, n, d) write(*,'(9(f4.1))') buf end program main C:\gfortran\clf\repeatdouble>c:\gcc_equation\bin\x86_64-pc-mingw32-gfortran -c r epeatdouble.f90 C:\gfortran\clf\repeatdouble>c:\gcc_equation\bin\x86_64-pc-mingw32-gfortran test 3.f90 repeatdouble.o -otest3 C:\gfortran\clf\repeatdouble>test3 0 0 537 1 0 3 2293200 2293200 0 537 1 0 3 repeat 4 times ... double 3.1415927410125732 . array : 1.00000000000000000 2.0000000000000000 3.000000000000000 0 4.0000000000000000 making copy nb 1 of 4 making copy nb 2 of 4 making copy nb 3 of 4 making copy nb 4 of 4 3.1 3.1 3.1 3.1 5.0 6.0 7.0 8.0 9.0 So it seems that the structure constructor for type(descr) isn't assigning that first member, address. If you do it by hand everything works. This is a pretty recent version of gfortran, so I think that the above example shows a bug in the compiler. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end |