Search code examples
fortran

convert to a derived type using transfer fortran intrinsic : does the standard advise for byte order?


I convert -using the intrinsic transfer - a integer(c_int32_t) to a derived type composed of four bytes, does the standard says anything about the order of the bytes after conversion

program transfert_ex
  use iso_c_binding
  implicit none
  integer(c_int32_t) :: res

  type :: pixel 
    integer(c_int8_t) :: r
    integer(c_int8_t) :: g 
    integer(c_int8_t) :: b 
    integer(c_int8_t) :: alpha
  end type

  type(pixel) :: p1, p2
  
  integer(c_int32_t) :: rx = 33   !! 21
  integer(c_int32_t) :: gx = 28   !! 1C
  integer(c_int32_t) :: bx = 128  !! 80
  integer(c_int32_t) :: ax = 255  !! FF

  res = ieor(ishft(rx, 24), ieor(ishft(gx, 16), ieor(ishft(bx, 8), ax)))
  p2 = transfer(res, p1)
  !print "(4(z0,1x))", [p2%r, p2%g, p2%b, p2%alpha]
  print *, ichar(transfer([p2%r, p2%g, p2%b, p2%alpha], 'a', 4))

end program transfert_ex

returns

211C80FF
     255         128          28          33

It seems that the bytes are flip from left to right after the conversion. I test with three differents compilers (on the same architecture which is little endian) and it gives the same result. So maybe the order of the bytes in the derived type in taken into account by the standard ?


Solution

  • The bit manipulation procedures for integers like ieor() or ishft() use a Bit model defined in section 16.3 in the Fortran 2018 standard. It defines a sequence of bits from the most significant bit being the leftmost and the the least significant bit the rightmost. It does not care about how exactly the integer is stored in memory in some bytes.

    If you do transfer() you will see how such an integers are stored in memory in individual bytes. On a little-endian architecture that order will seem reversed. This is not controlled by the standard at all. It is defined by the implementation of memory storage for integers on the particular CPU in the particular setting (some CPUs can be set for either big-endian or little-endian).