- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am attempting to pass a C++ array of pointers into a Fortran subroutine.
The C++ array is of a structure, which exactly conforms to a Fortran derived type.
So in C++ I have pArray* c_arr[DIM1][DIM2];
Then I call a Fortran sub, passing in the C++ array of pointers like fortsub(c_arr[0][0])
In Fortran I have Subroutine fortsub (fort_arr) where I need fort_arr to be a container for the array of pointers.
I currently do not know how to make this work, I have something like:
Type (type1), Dimension(2,*), Target :: fort_arr where type1 is the same type as pArray.
Basically, my problem is I don't know how to pass a double dimensioned array of C++ structure pointers into a Fortran subroutine.
I know that he concept of "array of pointers" does not exist in Fortran and the way you have to do it is have an array of derived type with a pointer component, but I cannot seem to get the data passing on the argument list correct.
Anyone have some advice, perhaps with a specific example? I would appreciate it greatly. Thanks.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Those are "integer pointers," or "Cray pointers," which don't operate with target, until you use c_f_pointer to make Fortran pointers of them. Also, a C ** isn't interoperable with Fortran arrays. I suppose you would need to "unlock" access individually to the 1D C arrays which would become interoperable arrays of integer pointers.
I'm not confident that I know what you mean about your C definitions. What you show doesn't look like a struct but may be a ***. I am more comfortable with things which ought to be directly interoperable.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I probably didn't explain the problem well enough with my example, and I will try to elaborate a bit more on Monday.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To make life easier (you may be doing this already) is on the C side, allocate the storage for the 2D array as one allocation (1D), Then independently allocate or use an additional 1D array of C pointers (# pointers = # rows), and fill in your pointers for C to use. Then on the call to Fortran, pass in the extents (#rows, #cols) and the pointer to the data blob (aka pointer[0] same as &(array[0][0]) .
On the Fortran side you can use the information to construct an array descriptor without copying the data. Caution, the indices are transposed between Fortran and C. Following data stored in memory in order of value depicted:
0 1 2 3
4 5 6 7
C has cell containing 6 as A[1][2]
Fortran has cell containing 6 as A(2,3) ! using 1-based indexing
You can construct an array descriptor that is 0-base if you desire (but cannot transpose the indexing)
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Note Fortran offers standard interoperability with C, not C++ so you will have to apply extern "C" linkage on your C++ side if you want to use standard approach.
Assuming you follow Jim's advice and go with 1D array of pointers to simplify the matter, here's an approach you can follow shown using C code:
#include <stdio.h> void C_printf(int** iptr, int M); void F_printf(int** iptr, int M); int main () { const int M = 3; int v[] = {1, 2, 3}; int *ptr; int i; for (i = 0; i < M; i++) { ptr = &v; /* assign the address of integer. */ } C_printf( ptr, M ); F_printf( ptr, M ); return 0; } void C_printf(int** iptr, int M) { printf("Print from C function:\n"); for (int i = 0; i < M; i++) { printf("Value of iptr[%d] = %d\n", i, *iptr); } }
module m use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_f_pointer contains subroutine somesub( c_iptr, size_i ) bind(c, name="F_printf") !.. Argument list type(c_ptr), intent(in) :: c_iptr(*) integer(c_int), intent(in), value :: size_i !.. Local variables integer(c_int), pointer :: f_i integer(c_int) :: i print *, " Print from Fortran subroutine:" do i = 1, size_i call c_f_pointer( c_iptr(i), f_i ) print *, "Value of iptr[",i,"] = ", f_i end do !.. return end subroutine somesub end module m
Upon execution,
Print from C function: Value of iptr[0] = 1 Value of iptr[1] = 2 Value of iptr[2] = 3 Print from Fortran subroutine: Value of iptr[ 1 ] = 1 Value of iptr[ 2 ] = 2 Value of iptr[ 3 ] = 3
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was thinking more along the line of: (untested code)
#include <stdio.h> void C_printf(int** iptr, int M); void F_printf(int** iptr, int M); int main (int argc, char* argv[]) { // get the unknown size of the 2D array int nRows = atoi(argv[1]); int nCols = nRows; // square array // allocate array as 1D int Aas1D* = (int*)malloc(nRow*nCols*sizeof(int)); // allocate an array of pointers to each row int** A = (int**)malloc(nRows*sizeof(int*)); // fill in the pointers to the rows for(int iRow=0; iRow<nCols; ++iRow) A[iRow] = &Aas1D[iRow * nCols]; // The array A[iRow][iCol] is now available // use the array for(int iRow = 0; iRow < nRows; ++iRow) for(int iCol = 0; iCol < nCols; ++ iCol) A[iRow][iCol] = iRow * 1000 + iCol; // insert data C_printf( A, nRows ); F_printf( &(A[0][0]), nRows ); F_printf( A[0], nRows ); F_printf( Aas1D, nRows ); return 0; } void C_printf(int** iptr, int M) { printf("Print from C function:\n"); for (int iRow = 0; iRow < M; iRow++) for(int iCol = 0; iCol < M; iCol++) { printf("Value of iptr[%d][%d] = %d\n", iRow, iCol, iptr[iRow][iCol]); } } module m use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_f_pointer contains subroutine somesub( c_iptr, size_i ) bind(c, name="F_printf") !.. Argument list type(c_ptr), intent(in) :: c_iptr integer(c_int), intent(in), value :: size_i !.. Local variables integer(c_int), pointer :: f_i(:,:) integer(c_int) :: iRow, iCol call c_f_pointer( c_iptr(i), f_i, [size_i, size_i] ) print *, " Print from Fortran subroutine:" do iRow = 1, size_i do iCol = 1, size_i print *, "Value of f_i(",iCol",",iRow,") = ", f_i(iCol, iRow) end do end do !.. return end subroutine somesub end module m
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank all of you for the tips, they are very much appreciated. I have something like the following, which seems to work now.
Note: Apologies, I am not too familiar with iso_C_binding, or what benefits it can bring to the table.
Most of my work has been done manipulating programs written in Fortran77/90, and I have added heavy usage of derived types and pointers, but haven't used modules. I have had great success in calling Fortran functions from C++, and do know about the reversed rows-columns for 2D arrays between C++ and Fortran.
So, what I have is this, which seems to work OK. In general, I am trying to avoid copying the data structures between C and Fortran.
Simply passing in the 2D array which is loaded with structure pointers will allow the Fortran subroutine to modify the C structures accordingly.
Also, will passing in the number of rows and columns for array bounds error-checking, just haven't done it yet.
C++ :
extern "C" struct MyStructC {
char s1[3];
int i1;
float f1;
};
extern "C" struct MyStructCPointerArray { MyStruct* pMyStructC; };
MyStructCPointerArray structvar[100][2]; // Local 2D C++ array which will contain pointers to MyStructC
for (int i=1; i<=2; ++i) { structvar[0][i-1].pMyStructC = getPointerToMyStructC(); } // Fill data with pointer(s)
fortfunc(&structvar[0][0]); // Call to Fortran
Fortran :
Type Declaration:
Type MyStructFortran
Sequence
Character(3) :: s1
Integer :: i1
Real :: f1
End Type MyStructFortran
Type MyStructFortranPointerArray
Sequence
Type (MyStructFortran), Pointer :: pMyStructFortran
End Type MyStructFortranPointerArray
Subroutine fortfunc (MyFortranVar)
! Argument List Variable Declarations
Type (MyStructFortranPointerArray), Dimension(2,*), Target :: MyFortranVar
! Local Variable Declarations
Integer :: i
! Local Pointer Declarations
Type (MyStructFortran), Pointer :: pStruct1, pStruct2
pStruct1 = MyFortranVar(1,1)%pMyStructFortran
pStruct2 = MyFortranVar(2,1)%pMyStructFortran
End Subroutine fortfunc
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John wrote:
... In general, I am trying to avoid copying the data structures between C and Fortran.
Simply passing in the 2D array which is loaded with structure pointers will allow the Fortran subroutine to modify the C structures accordingly. ..
It seems like you just need to pass an array of structs across from C++ to Fortran as the code in your second post doesn't quite jive with your explanations about an array of pointers in C++ needing to be used in Fortran. It's unclear why you even need an array of pointers. Why do you seem to think you are avoiding copying when you have a statement in Fortran such as "pStruct1 = MyFortranVar(1,1)%pMyStructFortran"?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I believe there is a difference between passing the entire 2D array of structures vs. passing a 2D array of pointers to the structures.
Wouldn't a copy of the entire 2D array be made is the first situation vs. no copy in the second situation?
Or is no copy made in the first situation, in which case I wouldn't need an array of pointers at all.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John wrote:
I believe there is a difference between passing the entire 2D array of structures vs. passing a 2D array of pointers to the structures.
Wouldn't a copy of the entire 2D array be made is the first situation vs. no copy in the second situation?
Or is no copy made in the first situation, in which case I wouldn't need an array of pointers at all.
No copy need be made, check it out yourself with your struct:
#include <stdio.h> typedef struct { int i; } foo_c; void C_printf(foo_c *f, int M); void F_printf(foo_c *f, int M); int main () { const int M = 3; int i; foo_c foo; for (i = 0; i < M; i++) { foo.i = i; } printf("Print from C main:\n"); for (int i = 0; i < M; i++) { printf(" address of foo[%d] = %d\n", i, &foo); } C_printf( foo, M ); F_printf( foo, M ); return 0; } void C_printf(foo_c *foo, int M) { printf("Print from C function:\n"); for (int i = 0; i < M; i++) { printf(" foo[%d].i = %d\n", i, foo.i); } for (int i = 0; i < M; i++) { printf(" address of foo[%d] = %d\n", i, &foo); } }
module m use, intrinsic :: iso_c_binding, only : c_int, c_loc, c_ptr implicit none type, bind(c) :: foo_f integer(c_int) :: i end type foo_f contains subroutine somesub( foo, size_i ) bind(c, name="F_printf") !.. Argument list type(foo_f), intent(inout), target :: foo(*) integer(c_int), intent(in), value :: size_i !.. Local variables integer :: i type(c_ptr) :: add_foo_i !.. print *, " Print from Fortran subroutine:" do i = 1, size_i print *, " foo%(",i,") = ", foo(i)%i end do do i = 1, size_i add_foo_i = c_loc(foo(i)) print *, " address of foo%(",i,") = ", add_foo_i end do !.. return end subroutine somesub end module m
Upon execution,
Print from C main: address of foo[0] = 2686540 address of foo[1] = 2686544 address of foo[2] = 2686548 Print from C function: foo[0].i = 0 foo[1].i = 1 foo[2].i = 2 address of foo[0] = 2686540 address of foo[1] = 2686544 address of foo[2] = 2686548 Print from Fortran subroutine: foo%( 1 ) = 0 foo%( 2 ) = 1 foo%( 3 ) = 2 address of foo%( 1 ) = 2686540 address of foo%( 2 ) = 2686544 address of foo%( 3 ) = 2686548
If you do plan to do more interoperation between C++ and Fortran via "extern C" linkage, do look into the facilities offered in Intel Fortran based on standard Fortran features from Fortran 2003 onward.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I understand what you are saying, but I cannot seem to get a 2D array to be passed in correctly.
If I declare my C array of structures as MyStructC* structvar[100][2];
then fill it with structure pointers and then pass it to Fortran like : fortfunc(structvar[0][0])
where in Fortran I have:
Subroutine fortfunc (MyFortranVar)
Type (MyStructFortran), Dimension(2,*), Target :: MyFortranVar
the first structure: MyFortranVar(1,1) is OK (meaning it contains the same data as structvar[0][0]), but MyFortranVar(1,2) is not OK (meaning it does not contain the same data as structvar[0][1].
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, I guess the only solution is to have an array of derived type with a pointer component: https://software.intel.com/en-us/forums/topic/280765. This is what my example above is doing, and it works well enough, I suppose.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>If I declare my C array of structures as MyStructC* structvar[100][2];
Add
MyStructC* MyStruct2DArray = new MyStructC[100*2];
for(int iRow = 0; iRow < 100; ++iRow)
for(int iCol=0; iCol < 2; ++iCol)
structvar[iRow][iCol] = &MyStruct2DArray[iRow*2 + iCol];
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
IOW allocate the blob of structures as one allocation (i.e. 1D array)...
Then construct your 2D array of pointers to these objects for use by C/C++.
Pass the address of the 1st element and have Fortran construct the array descriptor for the 2D array.
Be mindful that you may get your rows and columns mixed up (run test data to assure you have things right).
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you guys for this nice post.
I am new to this field, and am learning to do similar things as shown in #10 by FortranFan. When I compile his Fortran code with IVF, I obtain error #7300 The derived-type object in an input-output list cannot have the private components. After commenting lines on taking address of foo(i), the fortran code works well with integration into C++, but I cannot check the address as FortranFan did. Does anyone have any hint on how to get rid of the error? Many thanks.
QD
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Are you using an older version of the IFort compiler? If so, which one? It builds fine with the current compiler, 16.0.1.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Very interesting. 15.0 gives that error, 16.0 doesn't. 15.0 is correct - type C_PTR has a private component and you're not allowed to use it in an I/O list without a user-defined derived type I/O procedure. At first blush it looks as if we introduced a bug - I will look into it.
The correct way to do this would be to replace add_foo_i in the I/O list with TRANSFER(add_foo_i,0_INTPTR_T).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Looks as if we already fixed this as part of a number of other fixes to UDDTIO. The next major release will, once again, give an error for this use.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sorry that I did not make it clear. I am currently using Intel Composer XE 2013 sp1 which gives me this error.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, the error message is correct - the code in #10 is faulty but the 16.0 (2016) compiler doesn't give the error. That is an aberration.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve, thank you for the response.
I upgraded my IVF to 16.0 (2016), and made a DLL by adding
!DEC$ ATTRIBUTES DLLEXPORT :: somesub
below Line 13 subroutine
somesub( foo, size_i )
bind
(c,
name
="F_printf")
of the Fortran code in #10.
After modifying Line 08 void
F_printf(foo_c *f,
int
M);
with extern "C" {} in the C code, I am able to call the Fortran subroutine somesub from intel C++ 16.0 with MSVS2012.
Unlike what is shown in #10, in my output, the address of foo%(i) is different from that of foo. It seems that copy has been made, which is not desired in my application. If I am passing an array of structs (the array dimension is well defined in C++) to Fortran, what is the proper implementation without invoking unnecessary copy as discussed by John in #7 or #9? Sticking to the example in #10 is more appreciated.
QD

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page