0
votes

I have an legacy Fortran code that I want to mix with a new C/C++ program.

The Fortran subroutine allocates dynamically some arrays that I want to pass to c program. I will only get the size of these arrays after running the Fortran code.

After getting some tips here in this forum I arrived to the following code that I thought it would best compile, link and run.

Actually I can compile my C code and my Fortran code separately, but it doesn't link giving the following errors:

undefined reference to _gfortran_runtime_error

undefined reference to _gfortran_os_error

I'm using g++ and GFortran compilers version 5.4.0, and linking both .o files with g++ and the option -lg fortran.

fortran code:

subroutine test_allocation(outp) bind(c)
    use iso_c_binding
    implicit none
    type (c_ptr), value :: outp
    integer, target ::b(2)
    integer(c_int), pointer :: a(:)
    b(1)=1
    b(2)=2
    allocate(a(2))
    a=>b
    call c_f_pointer(outp, a,[2])
end subroutine

c code:

#include <iostream>
using namespace std;
extern "C" void test_allocation(int ** ptr);
int main ()
{
        int* ptr;
        test_allocation(&ptr);
}

EDIT:

As Vladimir F said on comments there was a mistake in my compiler option. The correct is -lgfortran.

Now it's linking but the results is not what I expect. I change a little my code to show this:

Fortran code:

subroutine test_allocation(outp) bind(c)
    use iso_c_binding
    implicit none
    type (c_ptr), value :: outp
    integer, target ::b(2)
    integer(c_int), pointer :: a(:)
    b(1)=1
    b(2)=2
    allocate(a(2))
    a=>b
    print*, "a(1) in Fortran: ", a(1)
    print*, "a(2) in Fortran: ", a(2)
    call c_f_pointer(outp, a,[2])
    print*, "outp after c_f_pointer: ",  outp
end subroutine

C code:

#include <iostream>

using namespace std;

extern "C" void test_allocation(int** ptr);



int main ()
{
        int* ptr;
        test_allocation(&ptr);
        cout<<"ptr[0] in C: "<< ptr[0]<<endl;
        cout<<"ptr[1] in C: "<< ptr[1]<<endl;

}

The output is:

a(1) in fortran:            1
a(2) in fortran:            2
outp after c_f_pointer:       140726088663920
ptr[0] in C: 1447122753
ptr[1] in C: 1107265857

I also tried changing the declaration of extern function to the following and it still does not work:

extern "C" void test_allocation(int*& ptr);
... 
test_allocation(ptr);

The output is:

a(1) in fortran:            1
a(2) in fortran:            2
outp after c_f_pointer:       140729541703872
ptr[0] in C: 1447122753
ptr[1] in C: 1107265857
1
I don't know why you have the error, but the code is incorrect, you cannot pass the pointer by value. Please show us your complete commands and the complete error output. Do not just select two lines. You can take the welcome tour and read How to Ask. - Vladimir F
You write -lg fortran with a space. Is that a typo? Is that a typo just here or also in your linking? Please show the complete commands and outputs. - Vladimir F
Ok, sorry. I changed to -lgfortran and it linked. Thanks. But it is still not giving me correct results as you can see in mey answer. - Marcus Muniz
Yes, I already wrote in my very first sentence that your code is wrong. - Vladimir F

1 Answers

0
votes

Now it works. Instead of using C_F_POINTER I used the function C_LOC.

I also removed the parameter VALUE from the TYPE(C_PTR) declaration.

Here is the code:

subroutine test_allocation(outp) bind(c)
    use iso_c_binding
    implicit none
    type (c_ptr)    :: outp
    integer  ::b(2)
    integer,dimension(:), pointer :: a
    b(1)=1
    b(2)=2
    allocate(a(2))
    a=b
    print*, "a(1) in fortran: ", a(1)
    print*, "a(2) in fortran: ", a(2)
    outp=c_loc(a)
    print*, "outp after c_loc: ",  outp
end subroutine

and it's output:

a(1) in fortran:            1
a(2) in fortran:            2
outp after c_loc:              36866928
ptr[0] in C: 1
ptr[1] in C: 2

The following link helped me a lot although I'm not using intel compiler:

https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/269660