integerfortranunsignedfortran95fortran2003

accessing unsigned integer values in fortran


If I have a c_int8_t variable in Fortran and want to interpret the underlying bits as an unsigned integer (for indexing rather than for any arithmetic) what is the most efficient way to do the conversion? I want to do something like

X( some_function( my_c_int8_t_var ) ) = 1

where X is an array and some_function should return a c_int16_t containing the unsigned value of my_c_int8_t_var. I have seen options including transfer, iadd (or I guess just a simple conditional with a cast and an addition) but I would like to know what would be the most efficient way (this indexing is taking place in an inner loop). Of course it doesn't have to be a function - if it can be done with an inline expression that would be great.

EDIT: It would be nice if the approach would also work for other integer size... ie for getting the contents of unsigned c_int16_t in a c_int32_t and getting an unsigned c_int32_t into a c_int64_t.


Solution

  • You could use transfer() and ichar() functions. Something like

    X(ichar(transfer(my_c_int8_t_var,"a")))) = 1
    

    For example

     use iso_c_binding
     write (*,*) ichar(transfer(-1_c_int8_t,"a"))
    
     end
    

    returns 255.

    When you cannot find a coresponding character kind (e.g., 16bit) I would write a function that adds huge(1._my_integer_kind) to the value.

    integer function indx(i)
      integer(c_int16_t),intent(in) :: i
    
      if (i<0) then
        indx = 2*(huge(i)+1) + i
      else
        indx = i
      end if
    end function indx
    

    or

      integer function indx2(i)
        integer(c_int8_t),intent(in) :: i
    
        indx2 = TRANSFER([i,0_c_int8_t],1_c_int16_t)
      end function indx2
    

    This last case works only for little-endian platforms.

    You can make a generic interface to this function.

     write (*,*) indx(-2_c_int16_t)
    

    gives 65534