2

I'm trying to get a Fortran code base to call a C library call using ISO_C_BINDING, but I am having trouble with passing the Fortran array.

I have created a simple example that illustrates my problem.

main.f90

program main
    use iso_c_binding
    implicit none

    interface
            subroutine stuff(s,d) bind(c,name='doStuff')
                    import :: c_char
                    import :: c_ptr
                    import :: c_double

                    character(c_char), value :: s
                    type(c_ptr), value :: d
            end subroutine stuff
    end interface

    character(len=1) ::c1
    real, allocatable :: d1(:)

    c1 = 'a'
    allocate ( d1(0:10) )

    d1(0) = 2.0
    d1(1) = 2.5
    d1(2) = 3.0
    d1(3) = 4.0

    write (*,*) d1

    call stuff(c1,c_loc(d1))

end program main

func.c

//a function
int doStuff (char c, double* w)
{
    printf("%c\n",c);
    printf("%d %d %d %d\n",w[0], w[1], w[2], w[3]);
    return 1;
}

compile line

icc -c func.c
ifort -o magic.go main.f90 func.o

output

2.000000       2.500000       3.000000       4.000000      0.0000000E+00    0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
a
0 -1938231792 1 1

The char is being passed correctly but the array isn't and I am at a loss how to correct it. The examples I've seen suggest changing

double* w

to

void* w

but I can't do that as I can't change the library code to make this work. I just tried creating a new function to cast a void* to double* to no effect :(. Likewise changing the array so that it is not allocatable would be infeasible.

Thoughts?

2

1 Answer 1

3

You have a problem with the declaration of d1. Better would be

real(c_double), allocatable, target :: d1(:)

That is: it needs to be the correct kind to be interoperable with C's double; to be an argument to c_loc it must have either the target or pointer attribute.

Also, as noted by Mahonri Moriancumer your printf format isn't appropriate for the double. And, possibly, having stuff as a function rather than a subroutine may be worth considering.

Sign up to request clarification or add additional context in comments.

3 Comments

The important part is real(c_double): I just remain surprised by how uncaring ifort is about attributes for c_loc.
Why target attribute is needed here? I tested with the target attribute, and the code still works fine
@SangjunLee, the target or pointer attribute is required by the Fortran standard (see F2018 18.2.3.6) for arguments to c_loc. Although some compilers (notably ifort) don't care and have things seem to work, for maximum correctness and portability it is desirable to have one of those attributes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.