我正在使用c_类型将fortran库与python连接起来。我用python初始化结构,将它们传递给fortran,由fortran填充它们,然后用python读回它们。使用数字数组时一切都很好,但现在我只能使用接口字符串数组
我尝试过这样的例子one,这没问题,但在本例中,c_char数组不在结构中。因此,我试图修改前面的示例,将c_char数组放入一个结构中。以下是我使用的代码,有结构和没有结构:
Python代码:
from ctypes import *
lib = CDLL("./libf.so")
if 1:
print(">>> Without structure")
func = getattr(lib, "fortran2py_")
nstring = pointer(c_long(2))
carr = (c_char * 255)()
func.argtypes = [POINTER(c_long), POINTER(c_char)]
print(type(carr))
print('before:',carr)
func(nstring, carr)
str1, str2 = ''.join([v.decode("utf-8") for v in carr]).rstrip("\x00").split("\x00")
print(str1, str2)
class Struct0(Structure):
_fields_ = [
("name", c_char * 255),
]
if 1:
print(">>> With structure")
func = getattr(lib, "fortran2pystr_")
nstring = pointer(c_long(2))
carr = Struct0()
func.argtypes = [POINTER(c_long), POINTER(Struct0)]
print(type(carr.name))
print('before:',carr.name)
func(nstring, byref(carr))
print('after:',carr.name)
Fortran代码:
module c_interop
use iso_c_binding
implicit none
integer, parameter :: STRLEN = 64
type, bind(c) :: charStr
character(c_char) :: name(255)
end type charStr
contains
subroutine fortran2py(nstring, cstring_p) bind(C, name="fortran2py_")
integer(c_int), intent(in) :: nstring
character(c_char), dimension(*), intent(inout) :: cstring_p
integer :: i, j, ks, kf, n
character(len=STRLEN) :: mystr(2)
mystr(1) = "This is the first string."
mystr(2) = "Wow. Fortran + Python + Strings = Pain !"
ks = 1
do i = 1, nstring
n = len_trim(mystr(i))
kf = ks + (n - 1)
cstring_p(ks:kf) = transfer(mystr(i)(1:n), cstring_p(ks:kf))
cstring_p(kf + 1) = c_null_char
ks = ks + n + 1
enddo
end subroutine fortran2py
subroutine fortran2pystr(nstring, cstring_p) bind(C, name="fortran2pystr_")
integer(c_int), intent(in) :: nstring
type(charStr), intent(inout) :: cstring_p
integer :: i, j, ks, kf, n
character(len=STRLEN) :: mystr(2)
mystr(1) = "This is the first string."
mystr(2) = "Wow. Fortran + Python + Strings = Pain !"
ks = 1
do i = 1, nstring
n = len_trim(mystr(i))
kf = ks + (n - 1)
cstring_p%name(ks:kf) = transfer(mystr(i)(1:n), cstring_p%name(ks:kf))
cstring_p%name(kf + 1) = c_null_char
ks = ks + n + 1
enddo
end subroutine fortran2pystr
end module c_interop
我没有得到任何错误,除了在修改的部分中,Fortran应该填充mystr元素上循环的c_char carr.name数组,但是结果字符串只包含第一个元素。当carr不是一个结构而直接是c_char数组时,python可以读取mystr的所有内容
输出:
>>> Without structure
<class '__main__.c_char_Array_255'>
before: <__main__.c_char_Array_255 object at 0x151b3b092bf8>
This is the first string. Wow. Fortran + Python + Strings = Pain !
>>> With structure
<class 'bytes'>
before: b''
after: b'This is the first string.'
正如您所看到的,carr和carr.name的类型也不相同。你知道我修改过的代码有什么问题吗?谢谢大家!
清单[Python 3.Docs]: ctypes - A foreign function library for Python
原因是一种微妙的行为c_char(以及c_wchar)数组在结构中以字段形式出现时,会自动转换为字节(或str)。这是通过c\u char\u p(或c\u wchar\u p)完成的,它们是num终止的,这意味着如果遇到num(0x00)字符,“数组”将被截断,这正是您的情况。您可以通过查看字段类型来检查这一点
我不知道这是为什么(可能是为了方便使用),但在某些情况下,它弊大于利。它只能用Python代码复制
code00.py
输出:
注释:
ctypes.POINTER(ctypes.c_char)
的结构也是可能的,但它会更复杂一些(而且,我没有测试它)相关问题 更多 >
编程相关推荐