Home > Mobile >  How do you pass a 2d array to an external function when the precise shape is determined at runtime i
How do you pass a 2d array to an external function when the precise shape is determined at runtime i

Time:01-05

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?

CodePudding user response:

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
  • Related