Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Incorrect value returned by ISO_C_binding "c_intptr_t" in Fortran / Mac OS X

Tags:

c

macos

gcc

fortran

I have the following Fortran function create_pointer that calls a C function named create_pointer that creates a pointer and returns its address:

FUNCTION create_pointer() RESULT(c_intptr_t) BIND(C, name = "create_pointer")
    USE, INTRINSIC :: iso_c_binding, ONLY: c_intptr_t
END FUNCTION

For reference, the C function create_pointer is the following:

intptr_t create_pointer(void)
{
    void *ptr;
    intptr_t address;

    ptr = malloc(100);
    address = (intptr_t) ptr;
    printf("FROM C: address %p\n", address)
    return address;
}

Now, when compiling (using GCC 4.9) and executing the following Fortran program in Mac OS X 64 bit:

PROGRAM

    INTEGER(c_intptr_t) :: address

    address = create_pointer()

    WRITE(*, '(Z8)') "FROM FORTRAN:", address

END PROGRAM

It gives an unexpected output which could be similar to this:

FROM C: address 0x7f8870c3ee00
FROM FORTRAN: address 70C3EE00

Why is the address being displayed in C different from the one in Fortran? I would assume that ISO_C_binding c_intptr_t would preserve the correct value between these two languages. Additionally, as one can notice, the address that Fortran receives from C is contained within it (in other words, the initial value 0x7f88 is discarded). Is it because only the first 48 bit in a 64 bit address count and the ISO_C_binding discards the last 16 bit?

FYI, when compiling (using GCC 4.9) and running the same Fortran program this time in Ubuntu 64 bit, the output is consistent (i.e. both the address that C and Fortran display are the same).


1 Answers

Your error is here:

FUNCTION create_pointer() RESULT(c_intptr_t) BIND(C, name = "create_pointer")

You are supposed to put a variable name inside the result part of a function declaration. Then you can use the name you put there inside the body of the function, and the value it has when the function terminates will be the result value returned by the function.

In your code, you put the name c_intptr_t, which coincides with the name you just imported from the intrinsic module and you effectively overrides it. I don't think that's the intention.

Also, as said by @francescalus, you do not have implicit none, so you let the default implicit rules of Fortran choose the type of your result variable; and it chooses default real (because the variable name starts with the letter C) - that's why the pointer is 32 bits in size.

c_intptr_t is a constant inside the intrinsic module iso_c_binding meant to be used as a type parameter for interoperable integer that get the correct pointer size of the system.

You could change the name of the variable inside result, for example to ptr, and change your function declaration to this:

function create_pointer() result(ptr) bind(C, name = "create_pointer")
  use, intrinsic :: iso_c_binding, only: c_intptr_t
  implicit none
  integer(c_intptr_t) :: ptr
end function
like image 94
Rodrigo Rodrigues Avatar answered Oct 18 '25 06:10

Rodrigo Rodrigues



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!