2

I have a c++ program that looks as following:

using namespace std;
extern"C" {
void fortfunc_(int a[][4], int *size_x, int *size_y);
}
int main()
{
    // size_x and size_y are dynamically determined at runtime
    // setting them here directly for simplification
    int size_x = 5;
    int size_y = 4;

    //we need to use 4 instead of size_y to prevent a mismatch with the int a[][4] definition in fortfunc_
    int foo [size_x][4]; 
    
    for (int i=0 ; i<size_x ; i++ )
    {
        for (int y=0 ; y<size_y ; y++ )
        {
            foo[i][y] = i+y;
        }
    }
    fortfunc_(foo, &size_x, &size_y);
    return 0;
}

The respective fortran program only prints the array and looks like this:

subroutine fortfunc(foo, size_x, size_y)
    use :: ISO_C_BINDING
    integer :: size_x, size_y   
    integer(c_int), dimension(size_y,size_x), intent(in) :: foo
    integer :: i, y
    do y = 1, size_x ! We reverse the loop order because of the reverse array order in fortran
        do i = 1, size_y
            print*, "col ",i,y, foo(i,y)
        end do
        print*, "row"
    end do
    return
end

When compiled with gfortran -c testF.f90 && g++ -c testC.cpp && g++ -o test testF.o testC.o -lgfortran && ./test this works.

However, I would like to be able to dynamically determine the shape of the 2d array foo in my main function and call my external fortfunc_ function accordingly, instead of hardcoding int a[][4] there. How can I modify my program to accomplish that?

Yes
  • 339
  • 3
  • 19
  • 3
    `int foo [size_x][4];` - whichever C++ textbook showed you to do this -- you need to throw it away immediately, and get a different C++ textbook. If you copied that off some web site, don't visit that web site any more. If you saw this in some clown's Youtube video, unsubscribe from that channel, you're not learning proper C++. This is not standard C++, and many C++ compilers will refuse to compile this. – Sam Varshavchik Jan 04 '23 at 16:36

1 Answers1

3

You typically allocate a 1d vector and treat it as a 2d array.

Example:

#include <vector>

extern "C" {
// note the changed signature with `int* a` instead:
void fortfunc_(int* a, int *size_x, int *size_y);
}

int main() {
    int size_x = 5;
    int size_y = 4;

    // A 1d vector with size_y * size_x elements:
    std::vector<int> foo(size_y * size_x);

    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            // calculation for row-major order:
            foo[y * size_x + x] = y * size_x + x;
            // Note: Fortran uses column-major order so you may need to change
            // to `foo[x * size_y + y] = x * size_y + y;`
        }
    }
    fortfunc_(foo.data(), &size_x, &size_y);
    //            ^^^^^^
    // a pointer to the first `int` in the 1d vector
}

Output:

 col            1           1           0
 col            2           1           1
 col            3           1           2
 col            4           1           3
 row
 col            1           2           4
 col            2           2           5
 col            3           2           6
 col            4           2           7
 row
 col            1           3           8
 col            2           3           9
 col            3           3          10
 col            4           3          11
 row
 col            1           4          12
 col            2           4          13
 col            3           4          14
 col            4           4          15
 row
 col            1           5          16
 col            2           5          17
 col            3           5          18
 col            4           5          19
 row
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • I see. What if I had a lot of interaction with the 2d array in my c program, would it make sense to create a function that takes the pointer to the first element of the `foo` vector and casts it back into a 2d array, or is there a better solution than to always have this intermediate 1d vector to interface with a fortran program? – Yes Jan 04 '23 at 17:57
  • 1
    @Yes In a C++ program you'd typically encapsulate the 1d vector in a class and provide an `operator()` overload to access the elements. There are many examples here on SO for how you could do that. I made one [here](https://stackoverflow.com/a/58122229/7582247) for example – Ted Lyngmo Jan 04 '23 at 18:10