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