fortran66のブログ

fortran について書きます。

【メモ帳】Fortran 2018 C言語の相互運用 MFE §21.2

Modern Fortran Explained - 2018

Fortran2018 で導入された Fortran と C の interoperability について、少しづつ試してゆきたいと思います。 MFE にはコード断片しかないので、残りを適当に埋めて、実行可能な形にして試していみることにします。

§ 21.2 Fortran optinal 引数と C 言語の通用

C 言語の関数 strtod (string to double) をインターフェースだけ書いて呼び出します。C 言語には文法上 optional 引数は無いのですが、null を送ることで optional 引数を実現しているようです。組み込みライブラリ関数 strtod はそのような仕組みを用いているようです。

参照: C言語関数辞典 - strtod

strtod は第一引数に文字列を与えると、その文字列先頭部を倍精度の数値として解釈して倍精度実数として返します。第二引数は optional で、ポインタを与えると、数値として解釈できなくなったところから文字列を返します。

ソース・プログラム

ポインタを Fortran 文字列にするのがこれでいいのかどうか。

module test_m
    implicit none
    interface
        function strtod(string, final) bind(c, name='strtod')
            use, intrinsic :: iso_c_binding
            character(kind=c_char), intent(in) :: string(*)
            type(c_ptr), optional, intent(in) :: final
            real(c_double) :: strtod
        end function strtod
    end interface
end module test_m


program main
    use, intrinsic :: iso_c_binding
    use test_m
    implicit none
    real(c_double) :: x, y
    type(c_ptr) :: yfinal
    character(80), pointer :: text

    x = strtod("3.1415926e2"//c_null_char)
    y = strtod("3.1415926d2"//c_null_char, yfinal)

    print *, x
    print *, y
    call c_f_pointer(yfinal, text)
    print *, text(:index(text, c_null_char) - 1)
end program main

実行結果

3.1415926e2 は e2 が 102 と解釈されましたが、3.1415926d2 は d2 の部分が解釈されずに吐き出されました。

gfortran 7,8,9

hp8@HP8:~/f2018$ gfortran-7 strtod.F90
hp8@HP8:~/f2018$ ./a.out
   314.15926000000002
   3.1415926000000001
 d2

ifort 19 文字列でない・・・

   314.159260000000
   3.14159260000000

Modern Fortran Explained: Incorporating Fortran 2018 (Numerical Mathematics and Scientific Computation)

Modern Fortran Explained: Incorporating Fortran 2018 (Numerical Mathematics and Scientific Computation)

C から Fortran の optional 引数を使う場合

ソース・プログラム

module test_m
    implicit none
contains
    subroutine fortran_note(main, minor) bind(c, name='fortran_note')
        use, intrinsic :: iso_c_binding
        integer(c_int), value :: main
        integer(c_int), optional :: minor
        if (present(minor)) then
            print '(1x, "Note ", I0, ".", I0)', main, minor
        else
            print '(1x, "Note ", I0)', main
        end if
    end subroutine fortran_note
end module test_m
void fortran_note(int main, int* minor);

int main(void) {
    fortran_note(10, (int *)0);

    int subnote = 3;
    fortran_note(10, &subnote);

    return 0;
}

実行結果

gfortran 7,8,9

hp8@HP8:~/f2018$ gfortran c_note.c note.f90
hp8@HP8:~/f2018$ ./a.out
 Note 10
 Note 10.3

ifort/icc 適せつなリンクの仕方が分からない・・・

icc からは fortran I/O ランタイムが呼べず、ifort では main が無いと言われる・・・