fortran66のブログ

fortran について書きます。

【メモ帳】sequence か、はたまた bind(c) か?

padding させないためには、sequence か bind(c) か?

派生型変数を一括書き出しするとき、データのバイト数が中途半端だとコンパイラが適当に並べ直したり、padding してデータ境界を調整しますが、それをさせずにあくまで宣言したとおりの順序と大きさで並べて欲しい時もあります。(データフォーマットの決まったバイナリ・ファイルの書き出しとか) 

今まで sequence を使ってきましたが、コンパイラによっては並びの順序は変えないものの padding はするようなものもあるような話は聞いていました。

最近の Dr. Fortran のブログ記事を読んで sequence がいいのか bind(c) がいいのか気になってきたので確かめてみました。 stevelionel.com

結論から言うと、gfortran はどちらも宣言通り、intel fortran では sequence は宣言通りで、bind(c) は padding するでした。つまり sequence にすればよろしいあるヨ。

program test
    implicit none

    c : block
        use, intrinsic :: iso_c_binding
        type, bind(c) :: c_t
            character(c_char) :: c = 'c'
            integer(c_int16_t) :: i1 = 12345
            integer(c_int64_t) :: i2 = 123456789
        end type c_t 
        type(c_t) :: ct
        integer :: n

        inquire(iolength = n) ct
     !   print *, c_sizeof(ct), sizeof(ct)
        print *, 'bind_c   iolength =', n, 'bytes', storage_size(ct) / 8, 'bytes'
        open(9, file='bindc.9', access='stream', status='replace')
        write(9) ct
        close(9)
    end block c
    
    f : block
        use, intrinsic :: iso_fortran_env
        type :: f_t
            sequence
            character :: c = 'f'
            integer(int16) :: i1 = 12345
            integer(int64) :: i2 = 123456789    
        end type f_t
        type(f_t) :: ft
        integer :: n

        inquire(iolength = n) ft
        print *, 'sequence iolength =', n, 'bytes', storage_size(ft) / 8, 'bytes'
        open(9, file='bindf.9', access='stream', status='replace')
        write(9) ft
        close(9)
    end block f    
end program test

intel fortran は I/O の record length が word 単位なので -assume byterecl のコンパイル時オプションで単位を byte に変えてやる必要があります。

$ gfortran bindc.f90
$ ./a.out
 bind_c   iolength =          11 bytes          16 bytes
 sequence iolength =          11 bytes          16 bytes

$ ifort -assume byterecl bindc.f90
bindc.f90(24): 警告 #6379: 構造体は 1 つ以上のアライメントされていないフィールドを含んでいます。   [F_T]
        type :: f_t
----------------^
$ ./a.out
 bind_c   iolength =          16 bytes          16 bytes
 sequence iolength =          11 bytes          11 bytes

Modern Fortran: Building efficient parallel applications

Modern Fortran: Building efficient parallel applications

  • 作者:Curcic, Milan
  • 発売日: 2020/10/06
  • メディア: ペーパーバック

Modern Fortran: Style and Usage

Modern Fortran: Style and Usage