How do I pass a 2D array in C++ to a Fortran subroutine?

前端 未结 3 1512
暖寄归人
暖寄归人 2020-12-29 16:27

I am writing a small C++ program which passes a 2-D array (of complex numbers) to a Fortran subroutine and receives it back filled with values. I wrote a version which passe

相关标签:
3条回答
  • 2020-12-29 16:35

    Multidimensional arrays in Fortran are stored as flat column-major arrays in memory. They are not pointers to pointers—they're really just 1D arrays where you have to do some extra arithmetic to compute array indices.

    The correct way to pass the array from C++ is like this:

    extern "C" void carray_(struct cpx *A);
    ...
    struct cpx A[2*2];
    carray_(A);
    
    complex<double> P[2][2];
    for(int i = 0; i < 2; i++)
    {
        for(int j = 0; j < 2; j++)
        {
            // note order of indicies: A is column-major
            P[i][j] = std::complex<double>(A[j*2 + i].r, A[j*2 + i].i);
        }
    }
    
    0 讨论(0)
  • 2020-12-29 16:46

    The way to do this in this era is to use the ISO C Binding. Officially this is part of Fortran 2003, but is is widely supported by Fortran compilers, including gfortran. It even includes interoperability of complex types! See the list of types in the gfortran manual under the chapter "Intrinsic Modules", section "ISO_C_Binding". Plus there are several examples in the chapter "Mixed-Language Programming". On the C++ side, use extern C for the routine to be called in order to use C calling conventions without name-mangling. On the Fortran side, use the ISO C Binding. Then you will have compatibility at the language level rather than having to make assumptions about how the compilers work.

    0 讨论(0)
  • 2020-12-29 17:02

    New advice

    A two-dimensional array in c++ is not--I repeat not--the same as a pointer to a pointer{*}!

    When you do

    struct cpx** A;
    

    you are setting up to construct a so called "ragged array" for which there is not a fortran equivalent. You want something like

    struct cpx *A[2][2] = new struct cpx[2][2];
    

    which is a pointer to a two-dimensional array with rows 2 long.

    {*} Yes, you can access a pointer-to-pointer structure using the two-dimensional array notation, but they are laid out differently in memory. ::grumble:: People who tell other people that arrays and pointers are the same thing in c need to meet the Big Foam Clue Bat.

    • A two dimensional array is a single allocation of <row-dimension>*<column-dimension>*sizeof(<type>). It's name decays to a pointer-to-type.
    • A ragged array is 1+ allocation. The one is <column-dimension<*sizeof(<type>*) and the other are <row-dimension>*sizeof(<type>).

    Old, correct, but non-applicable advice

    The thing to be aware of here is that c++ and fortran believe arrays are stored differently in memory.

    C++ thinks that the memory position after a[1][1] is a[1][2], while fortran believes that is is a[2][1]. The distinction is between row-major (c, c++, etc) and column major (fortran, matlab, a few others).

    Note that this is separate from fortran indexing arrays from 1 by default.

    0 讨论(0)
提交回复
热议问题