Search code examples
c++fortranfortran-iso-c-binding

Why don't I have to specify that the result of a fortran function is being passed by value to my C++ program?


I am learning about fortran C++ interoperability. In this case I was trying to write a 'wrapper' function (f_mult_wrapper) to interface between my 'pure' fortran function (f_mult) and C++. The function is defined in my C code as

double f_mult_by_wrapper(double i, double j);

and called like

double u=f_mult_by_wrapper(w,r);

I know I must specify that the input arguments in f_mult_wrapper are being passed by value from C, and that fortran usually passes by reference. But the compiler gives me an error when I try to specify that the result is being passed by value: A dummy argument name is required in this context. The code works together as written, but I don't exactly understand why.

module type_example 
    use :: iso_c_binding
    function f_mult(i,j) result(k)
        ! use fortran intrinsic types
        real:: i,j,k
        k = i*j;        
    end function
    
    function f_mult_wrapper(aw,bw) result(cw) bind(c,name="f_mult_by_wrapper");
        real(c_double), VALUE :: aw ! use c binding types. passed by value
        real(c_double), VALUE :: bw
        real(c_double) :: cw
        real :: a,b,c
        a = aw
        b = bw
        c = cw
        c = f_mult(a,b)
        cw = c
    end function
end module

Solution

  • Function results are simply not function arguments/parameters. They are passed differently and the exact mechanism depends on the ABI (calling conventions) and their type.

    In some ABIs, results are passed on the stack. In other ABIs, they are passed using registers. That concerns simple types that can actually fit into registers. More complex objects may be passed using pointers (on the stack or in registers).

    The by value/by reference distinction distinguishes, whether the value of the argument is passed on the stack/in the register directly, or indirectly using a pointer. It does not concern function return values.

    There are simpler functions that can be C-interoperable and other Fortran functions that cannot be interoperable, e.g. functions returning arrays. Such Fortran-specific functions are implemented in a compiler-specific way. Often, a hidden argument is being passed. Such a hidden argument may contain a pointer and may be passed using a register or using the stack. The details are again dependent on the specific ABI.

    For the calling conventions to the most common x86 architecture, see https://en.wikipedia.org/wiki/X86_calling_conventions There are several different variations for 32 bit and for 64 bit.