由Python向Fortran中传输字符串
1.原理介绍

image.png
python中所有的字符串默认为Unicode字符串,故可以通过encode()、decode()方法进行转换。字符串数组在
ctypes中的行为更接近于C语言中的字符串数组,其需要采用二维数组的形式来实现,e.g.((c_char * 10) * 3)()
print("1-------------------")
charList = ((c_char * 10) * 1)()
print(chaeList[0].value)
print(charList[0].raw)
print("2-------------------")
strList = ['a一α']
charList[0] = ctypes.create_string_buffer(strList[0].encode(), 10)
print("3-------------------")
print(chaeList[0].value)
print(charList[0].raw)
# 输出结果 \xe4\xb8\x80 是"一".encode(), xce\xb1 是"α".encode()
>>1-------------------
>>b''
>>b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>2-------------------
>>3-------------------
b'a\xe4\xb8\x80\xce\xb1'
b'a\xe4\xb8\x80\xce\xb1\x00\x00\x00\x00'
上述的字符串数组实例可直接当做字符串指针传入
C函数,其行为等同于在C中声明的char (*)[10]指针由于
ctypes的字符串对象通过某个固定长度的字符串类实例化得到,故在赋值时,这样的字符串对象只可以接受等同于其声明长度的字符串对象作为替代值,这是普通Python字符串做不到的。要得到这样的定长字符串,需要用到ctypes的create_string_buffer函数。create_string_buffer函数用于创建固定长度的带缓冲字符串。其接受两个参数,第一参数为字符串,第二参数为目标长度,返回值即为被创建的定长度字符串对象,可以赋值给字符串数组中的某个对象。注意,create_string_buffer函数必须接受字节字符串作为其第一参数。
方法一
无需Fortran中需要预先分配大空间character,但是需要传入两个参数
subroutine writepath(x,N) bind(C, name="wPath")
use ISO_C_BINDING
implicit none
integer(c_int), intent(in), value :: N
character(kind=c_char) :: x(N)
write(*,*) x(1:N)
end subroutine
from ctypes import create_string_buffer, c_char, c_int
def string2fortran(strs):
lenStrs = len(strs.encode())
charList = ((c_char * lenStrs) * 1)()
charList[0] = create_string_buffer(strs.encode(), lenStrs)
return charList[0], c_int(lenStrs)
import ctypes as ct
fortlib = ct.CDLL(r'路径/动态链接库.dll')
writePath = getattr(fortlib, "wPath")
writePath.argtypes = [ct.POINTER(ct.c_char), ct.c_int]
filepath_chinese = r'字符串'
filepath, filepath_length = string2fortran(filepath_chinese)
writePath(filepath, filepath_length)
方法二
需要Fortran中需要预先分配大空间character,只需要传入一个参数
subroutine writePath(x) bind(C, name="writePath")
use ISO_C_BINDING
implicit none
character(kind=c_char), target :: x(9999) ! target 形容词不能少
character(9999), pointer :: ps=>null()
integer(kind=4) :: lens
call c_f_pointer(c_loc(x(1)),ps)
lens = index(ps, c_null_char)-1
write(*,*) ps(1:lens)
end subroutine
from ctypes import create_string_buffer, c_char
def string2fortran(strs):
lenStrs = len(strs.encode())
charList = ((c_char * lenStrs) * 1)()
charList[0] = create_string_buffer(strs.encode(), lenStrs)
return charList[0]
import ctypes as ct
fortlib = ct.CDLL(r'路径/动态链接库.dll')
writePath = getattr(fortlib, "writePath")
writePath.argtypes = [ct.POINTER(ct.c_char)]
filepath_chinese = r'字符串'
filepath = string2fortran(filepath_chinese)
writePath(filepath)