How to call a C function in Fortran and properly pass uint32_t arguments

半世苍凉 提交于 2019-12-13 13:55:00

问题


Hi I am using a Fortran 90 code to call a C function. Since I am manipulating addresses, the arguments of the C function should be properly matched in Fortran. I am using ifort and icc to compile the code and working on 64 bit machine.

Some testing showed that this will work also with int32_t, although to prevent eventual pitfalls, I would like to keep the uint32_t

The C functions I am calling has the following prototypes

uint32_t encode_(uint32_t x, uint32_t y)
uint32_t decode_(uint32_t dec)

I can't call these functions simply by doing something like

integer :: cod,encode
cod = encode(i,j)

This will produce gibberish. Therefore I am using a workaround:

void code2d_(uint32_t j[] ){


uint32_t i;

i=encode_(j[0],j[1]);  
// the underscore is due to the FORTRAN naming convention

printf("Coded %10d  \n",i);

}

And subsequently in Fortran

 integer :: cod,code2d
 cod = code2d(i,j)

Well obviously I have some problem with the mismatch of the argument types. Unfortunately I don't know how to fix this. Since in my decode/encode functions binary address arithmetic is done it is quite important to preserve the uint32_t.


回答1:


You appear to know about iso_c_binding, as you use the tag. Study the Fortran 2003 interoperability with C. Read the tag description and some documentation like http://gcc.gnu.org/onlinedocs/gcc-4.9.0/gfortran/Interoperability-with-C.html . There is no place in modern Fortran for your trailing underscores and similar stuff.

Fortran doesn't have any unsigned types, you have to use the signed. As long as the signed values are positive, it works. If you need larger values, use larger integer type. You can transfer() the lower bytes to int32 if you need it.

Third, Fortran uses some variants of pass by reference by default, especially for bind(c) procedures (it may be a reference to a copy or some other variant). You must use the value attribute to pass by value.

uint32_t encode(uint32_t x, uint32_t y)
uint32_t decode(uint32_t dec)

module c_procs
  interface
    function encode(x, y) bind(C, name="encode")
      use iso_c_binding
      integer(c_int32_t) :: encode
      integer(c_int32_t), value :: x, y
    end function
    function decode(x, y) bind(C, name="decode")
      use iso_c_binding
      integer(c_int32_t) :: decode
      integer(c_int32_t), value :: dec
    end function
  end interface
end module

...

use iso_c_binding
use c_procs

integer(c_int32_t) :: cod, i, j
cod = encode(i,j)

Recent versions of GCC are able to detect that we are mixing signed and unsigned types during link-time optimizations:

rng.f90:173:0: warning: type of 'sub' does not match original declaration [-Wlto-type-mismatch]
     ival = sub(jz, jsr)
^
rng_c.c:2:10: note: return value type mismatch
 uint32_t sub(uint32_t a, uint32_t b) {
          ^
/usr/include/stdint.h:51:23: note: type 'uint32_t' should match type 'int'
 typedef unsigned int  uint32_t;
                       ^
rng_c.c:2:10: note: 'sub' was previously declared here
 uint32_t sub(uint32_t a, uint32_t b) {

You can ignore the warning or disable it if you know what you are doing.




回答2:


You could write a C function which takes a C_INT (or int in C) and then converts it to uint32_t. Then you link to this from Fortran.

in C:

uint32_t to_uint32_t ( int i ) {
    return (uint32_t)i; //cast actually not needed since it implicitly converts
}

in fortran:

module convert
    interface
        integer(C_INT32_T) function integer_to_uint32_t_C ( i ) bind (c,name="to_uint32_t")
            use iso_c_binding
            use user32_constants_types
            integer(c_int), value :: i
        end function
    end interface

end module convert

Then you can use integer_to_uint32_t_C to pass Fortran integer values to C functions that expect the uint32_t. Also, you might want to make a C function that converts in back to a plain ole int so you can use the results in Fortran.



来源:https://stackoverflow.com/questions/24726446/how-to-call-a-c-function-in-fortran-and-properly-pass-uint32-t-arguments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!