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 を使うのが良いです)。
