FortranとC++のstringクラスでやり取りする

FortranではC言語の文字列(char[])位のやり取りをするついでに、C++のstringクラスとのやり取りも実験的に。
今回、画面側がMFCなので、CStringを使うかstringを使うか悩むところなのですが、まぁSTLをごりごり使うという前提でstd::stringを使ってみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module strmodule
    implicit none
contains
    ! 文字列を受け取る
    subroutine fstr1( str )
        character(*) :: str
        print *, "in fstr1:", str
    end subroutine fstr1
    ! 文字列を返す
    subroutine fstr2( str )
        character*80 :: str
        str = "masuda tomoaki"
    end subroutine fstr2
end module strmodule

Fortran側の module は、「character(*)」で文字列を受け取ります。逆に文字列を渡す場合には「character*80」のようにサイズを指定します。Fortranだけでで文字列を表示するときはいいのですが、C言語とやり取りする時にはうしろの空白が面倒なのです。Fortranの場合は、空きの分は空白で埋めてくれます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
extern "C" {
    void STRMODULE_mp_FSTR1( const char *str, int length );
    void STRMODULE_mp_FSTR2( char *str, int length );
}
// 文字列を設定
void FSTR1( string &str )
{
    STRMODULE_mp_FSTR1(str.c_str(), str.length());
}
// 文字列を取得
string FSTR2()
{
    static char buf[1000] = {0}; // 大きめのバッファ
    STRMODULE_mp_FSTR2( buf, sizeof(buf));
    string str = buf;
    int e = str.find_last_not_of(" ");
    if ( e != string::npos ) {
        str = string( str,0, e+1 );
    }
    return str;
}

なので、std::stringから、Fortranの関数に渡す時には長さを指定して、逆に受け取る場合には string::find_last_not_of で後ろの空白を削除する(trimする)という定番処理が必要になります。

1
2
3
4
5
6
7
8
// string クラスとの相互運用
string str = "masuda tomoaki";
// そのまま fortran に渡す
cout << "call FSTR1" << endl;
FSTR1( str );
// fortran から受け取る
str = FSTR2();
cout << "call FSTR2:[" << str << "]" << endl;

文字列の場合は、この変換が必要なので適当なマクロを作るか、関数を作るかするかなぁと。char[] のまま C++ で扱うのは厄介なので(今回、STLを使ってよいという話なので)、このあたりは適当に隠蔽したいところ。

本来ならば、unicode を気遣う必要があるのですが、今回は英語版なので…まあ良しとしましょう(ってのがi18nの問題でもあるのだけど、既にあるコードが string を使っているからね。Unicode に気を遣う場合は、MFC の時は CString を使うのが良いです)。

カテゴリー: C++, Fortran パーマリンク