【问题标题】:Fortran optional arguments in Python using ctypesPython中使用ctypes的Fortran可选参数
【发布时间】:2018-02-24 09:21:23
【问题描述】:

我应该如何使用 CTypes 在 Python 中正确处理可选的 Fortran 参数?例如,假设 Fortran 子例程类似于:

MODULE test_module
INCLUDES
   SUBROUTINE fstr_test(iunit, istat, file1, file2, file3, test, file4, file5)
      IMPLICIT NONE
      INTEGER, INTENT(inout) :: iunit
      INTEGER, INTENT(out) :: istat
      CHARACTER(LEN=*), INTENT(in) :: file1, file2, file3
      CHARACTER(LEN=*), INTENT(in), OPTIONAL :: file4, file5
      INTEGER, OPTIONAL :: test
      WRITE(6,*) file1, file2, file3
      RETURN
   END SUBROUTINE fstr_test
END MODULE test_module

现在python应该看起来像

import ctypes as ct
libtest = ct.cdll.LoadLibrary("libtest.so")
fstr_h = getattr(libtest,'__test_module_MOD_fstr_test')
fstr_h.argparse =     [ ct.c_int, \ #iunit
                        ct.c_int, \ #istat
                        ct.c_char_p, \ #file1
                        ct.c_char_p, \ #file2
                        ct.c_char_p, \ #file3
                        ct.c_int, \ #test
                        ct.c_char_p,\ #file4
                        ct.c_char_p, \ #file5
    ct.c_bool, ct.c_bool, ct.c_bool,\ # Three optional arguments
    ct.c_long, ct.c_long, ct.c_long, ct.c_long, ct.c_long] # lengths
fstr_h.restype=None
iunit_temp = ct.c_int(0)
istat_temp = ct.c_int(0)
record_in_temp = ct.c_int(0)
opt1 = ct.c_bool(True)
opt2 = ct.c_bool(True)
opt3 = ct.c_bool(True)
file1 = "one"
file2 = "two"
file3 = "three"
file4 = "four"
file5 = "five"
fstr_h(iunit_temp,ct.byref(istat_temp), \
    file1.encode('UTF-8'),file2.encode('UTF-8'),file3.encode('UTF-8'),\
    record_in_temp,file4.encode('UTF-8'),file5.encode('UTF-8'), \
    ct.byref(opt1), ct.byref(opt2), ct.byref(opt3),\
    len(file1),len(file2),len(file3),len(file4),len(file5))

从 gcc 在其argument passing conventions 上的文档中,我相信我正确地传递了变量,但我可能遗漏了一个微妙之处?当我尝试运行代码时它崩溃了。

【问题讨论】:

  • 您能否将您的(Python 端)参数与您理解的 gcc(通过参数传递约定)所期望的相匹配?这将帮助我(谁不做 python/ctypes)评估你的信念。
  • 什么是argparse?尝试设置 argtypes 属性。
  • 如果通过引用传递,您希望 argtype 为 ct.POINTER(ct.c_int) 以传递 ct.byref(iunit_temp),例如。您也可以使用file1 = b'one' 并显式跳过对文件进行编码。
  • 我切换到 argtypes 这并不能解决我的问题,但可能会修复我使用 argparse 的其他一些代码(请参阅此问题的解决方案 stackoverflow.com/questions/42328866/…

标签: python fortran ctypes gfortran


【解决方案1】:

好的,想出了一些办法。

  • 我需要使用argtypes 而不是argparse
  • OPTIONAL 参数仅在被定义为由 Fortran 中的 VALUE 传递时才需要隐藏的逻辑变量。如果它们没有被传递,那么仍然需要传递一个 NULL 指针。
  • 整数都需要通过引用传入。

所以 Fortran 代码保持如上,但 Python 代码应该是这样的

import ctypes as ct
libtest = ct.cdll.LoadLibrary("libtest.so")
fstr_h = getattr(libtest,'__test_module_MOD_fstr_test')
fstr_h.argtypes =     [ ct.POINTER(ct.c_int), \ #iunit
                        ct.POINTER(ct.c_int), \ #istat
                        ct.c_char_p, \ #file1
                        ct.c_char_p, \ #file2
                        ct.c_char_p, \ #file3
                        ct.POINTER(ct.c_int), \ #test
                        ct.c_char_p,\ #file4
                        ct.c_char_p, \ #file5
                        ct.c_long, ct.c_long, ct.c_long, ct.c_long, ct.c_long] # lengths
fstr_h.restype=None
iunit_temp = ct.c_int(0)
istat_temp = ct.c_int(0)
record_in_temp = ct.c_int(0)
file1 = "one"
file2 = "two"
file3 = "three"
file4 = "four"
file5 = "five"
fstr_h(ct.byref(iunit_temp),ct.byref(istat_temp), \
       file1.encode('UTF-8'),file2.encode('UTF-8'),file3.encode('UTF-8'),\
       ct.byref(record_in_temp),file4.encode('UTF-8'),file5.encode('UTF-8'), \
       len(file1),len(file2),len(file3),len(file4),len(file5))

现在这是猜想,但我怀疑在 Fortran 中键入为 INTNET(in) 的任何变量都可以作为值而不是指针传递。但是,由于INTENT(inout)INTENT(out)变量的值发生了变化,我相信需要通过指针传递。对于 Fortran 中定期输入的参数也可以这样说。

【讨论】:

  • 官方 Fortran 到 C 的互操作性要好得多。见fortran-iso-c-binding只有如果您使用bind(C),您可以计算可选参数使用NULL 指针这一事实。没有bind(C),编译器可以为所欲为。它还可以将奇怪的变形名称__test_module_MOD_fstr_test 更改为它想要的任何名称,它可能在编译器版本之间有所不同,并且它在不同的编译器之间有所不同。您也可以在那里阅读有关按引用传递和类似的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-13
  • 2021-07-28
  • 2011-03-08
相关资源
最近更新 更多