2017-02-19 9 views
2

ctypesを使用して共有ライブラリのFortranサブルーチンに引数を渡そうとしています。今ここに私の簡単なFortranコードです:私はこれが正常に動作するようですctypesを使用してFortranサブルーチンにPython文字列を渡す

gcc -shared -fPIC -o libtest.o fstr_test.f90 

でこれをコンパイル

MODULE test_module 
INCLUDES 
SUBROUTINE fstr_test(file_or_extension, ierr, iopen) 
    IMPLICIT NONE 
    INTEGER, INTENT(out) :: ierr 
    INTEGER, OPTIONAL :: iopen 
    CHARACTER(LEN=*), INTENT(in) :: file_or_extension 
    WRITE(6,*) file_or_extension,ierr,iopen 
    RETURN 
END SUBROUTINE fstr_test 
END MODULE test_module 

、私は実際にはPython 3での共有ライブラリをロードすることができますここでは、コード非クラッシュです:

は、
from ctypes import * 
libtest = cdll.LoadLibrary("libtest.so") 
f = libtest.test_module_MOD__fstr_test 
file = b'wout_li383.nc' 
ierr = c_int(0) 
iopen = c_int(0) 
cfile=c_char_p(b"test_str") 
f(cfile,byref(ierr),byref(iopen)) 

ただし、文字列を正しく渡すことができません。上の形式では、文字列は空であり、2つの整数はコンソールに正しく出力されます。基本的に私が行った唯一の進歩は、Pythonをクラッシュさせることです。私はここで解決策を試してみました:

Passing string to Fortran DLL using ctypes and Python

が、それはPythonの2話して、多分ので、私のために動作するようには思えないのですか?例

f.argtype = [c_char_p,c_int_c_int] 
c = c_char_p(b"test.txt") 
f(c,byref(ierr),byref(iopen)) 

については

は、カーネルをクラッシュしませんが、文字列は空です。 byrefに変更する:

同じ効果。長さ引数を追加して長さを渡して渡すと、 "Dead Kernel"というメッセージが表示され、カーネルを再起動する必要があります。 seのエラーメッセージはありません。

f.argtype = [c_char_p,c_int,c_int_c_int] 
file = b'text.txt' 
c = c_char_p(file) 
c_len = c_int(len(file)) 
f(c,byref(c_len),byref(ierr),byref(iopen)) 

これは明らかです。私はエラーメッセージを受け取っていない、カーネルはちょうど死んでいる。

+0

リンクされた質問の答えは、文字列の長さに "隠された"引数を渡すことについて話します(Cの相互運用可能な文字変数を使用しない場合の共通の方法)。あなたはここでそれをしないのですか? – francescalus

+0

なぜそれはうまく動作しないのですか?エラーメッセージ?間違った結果?見せる。 –

+0

文字列の長さを隠し変数として含めると、カーネルがクラッシュします。 – Lazer

答えて

2

いくつかの問題は、引数リストの最後に隠れた長さ(少なくともgfortranが他のコンパイラで何をしているか不明)が必要です。あなたはどちらかそれにByRefのを必要としないと

SUBROUTINE fstr_test(file_or_extension, ierr, iopen) 
    IMPLICIT NONE 
    INTEGER, INTENT(out) :: ierr 
    INTEGER, OPTIONAL :: iopen 
    CHARACTER(LEN=*), INTENT(in) :: file_or_extension 
    WRITE(6,*) file_or_extension,ierr,iopen 
    ierr=1 
    RETURN 
    END SUBROUTINE fstr_test 

gfortran -shared -fPIC -o libtest.so fstr_test.f90 

次にサブルーチンでIERR変数を変更c_char_p

でのpythonをバイト文字列をラップしていませんコードは次のようにする必要があります。

import ctypes 

lib=ctypes.CDLL("./libtest.so") 
f=getattr(lib,'__test_module_MOD_fstr_test') 

f.argtypes=[ctypes.c_char_p,ctypes.c_int,ctypes.c_int,ctypes.c_int] 
f.restype=None 

x=b'abcdef' 
ierr=ctypes.c_int(0) 
iopen=0 
f(x,ctypes.byref(ierr),iopen,len(x)) 
print(ierr.value) 

私はオプションの引数letを取得していませんが、だから私は空のintを追加しました、これはまだ文字列を渡す必要がありますし、ierrを取得します。

+0

あなたの例では 'argparse'か' argtypes'でしょうか? BTW-それはちょうどうまく動作するように感謝します。 – Lazer

+0

良いキャッチ、それはargtypesする必要があります – Rob

関連する問題