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

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

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の場合は、空きの分は空白で埋めてくれます。

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する)という定番処理が必要になります。

	// 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 パーマリンク