- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个库函数(用 C 语言编写),它通过将输出写入 FILE *
来生成文本。我想用创建临时文件或管道的代码将其包装在 Python (2.7.x) 中,将其传递给函数,从文件中读取结果,并将其作为 Python 字符串返回。
这里有一个简化的例子来说明我所追求的:
/* Library function */
void write_numbers(FILE * f, int arg1, int arg2)
{
fprintf(f, "%d %d\n", arg1, arg2);
}
Python 包装器:
from ctypes import *
mylib = CDLL('mylib.so')
def write_numbers( a, b ):
rd, wr = os.pipe()
write_fp = MAGIC_HERE(wr)
mylib.write_numbers(write_fp, a, b)
os.close(wr)
read_file = os.fdopen(rd)
res = read_file.read()
read_file.close()
return res
#Should result in '1 2\n' being printed.
print write_numbers(1,2)
我想知道我对 MAGIC_HERE()
的最佳选择是什么。
我很想只使用 ctypes
并创建一个返回 Python c_void_t 的 libc.fdopen()
包装器,然后将其传递到库函数中。我觉得这在理论上应该是安全的——只是想知道这种方法或现有的 Python 主义是否存在问题来解决这个问题。
此外,这将在一个长时间运行的过程中进行(让我们假设“永远”),因此任何泄漏的文件描述符都会有问题。
最佳答案
首先,请注意 FILE*
是一个特定于 stdio 的实体。它在系统级别不存在。存在于系统级别的东西是 UNIX 中的描述符(使用 file.fileno()
检索)(os.pipe()
已经返回普通描述符)和 Windows 中的句柄(使用 msvcrt.get_osfhandle()
检索)。 因此,如果可以有多个 C 运行时在运行,那么它作为库间交换格式是一个糟糕的选择。如果你的库是针对另一个 C 运行时而不是你的副本编译的,你就会遇到麻烦Python:1)结构的二进制布局可能不同(例如,由于对齐或用于调试目的的其他成员,甚至不同的类型大小); 2) 在 Windows 中,结构链接到的文件描述符也是特定于 C 的实体,并且它们的表由内部的 C 运行时维护 1 .
此外,在 Python 3 中,I/O 进行了全面检查,以便将其从 stdio
中解开。因此,FILE*
与 Python 风格(也可能是大多数非 C 风格)不同。
现在,你需要的是
fdopen()
(或等效的)。(毕竟,Python 的座右铭之一 是“让正确的事情变得容易,让错误的事情变得困难”)
最干净的方法是使用库链接到的精确实例(祈祷它是动态链接的,否则将没有要调用的导出符号)
对于第一项,我找不到任何 Python 模块可以分析加载的动态模块的元数据以找出它与哪些 DLL/so 链接(仅名称甚至名称+版本是不够的,你知道,由于系统上可能有多个库实例)。尽管这绝对是可能的,因为有关其格式的信息已广泛可用。
对于第二项,它是一个普通的 ctypes.cdll('path').fdopen
(_fdopen
用于 MSVCRT)。
其次,你可以做一个小的辅助模块,它会针对与库相同(或保证兼容)的运行时进行编译,并会为你从上述描述符/句柄进行转换。这是正确编辑库的有效解决方法。
最后,有一个使用 Python 的 C 运行时实例的最简单(也是最肮脏的)方法(因此上述所有警告完全适用)通过 Python C API 可通过 ctypes.pythonapi
获得。 .它利用了
stdio
的 FILE*
的包装器(Python 3 不是)PyFile_AsFile
返回包装的 FILE*
的 API(注意 it's missing from Python 3 )
fd
,您需要先构造一个类似文件的对象(以便返回一个FILE*
;))事实 id()
一个对象的是它的内存地址(特定于 CPython) 2
>>> open("test.txt")
<open file 'test.txt', mode 'r' at 0x017F8F40>
>>> f=_
>>> f.fileno()
3
>>> ctypes.pythonapi
<PyDLL 'python dll', handle 1e000000 at 12808b0>
>>> api=_
>>> api.PyFile_AsFile
<_FuncPtr object at 0x018557B0>
>>> api.PyFile_AsFile.restype=ctypes.c_void_p #as per ctypes docs,
# pythonapi assumes all fns
# to return int by default
>>> api.PyFile_AsFile.argtypes=(ctypes.c_void_p,) # as of 2.7.10, long integers are
#silently truncated to ints, see http://bugs.python.org/issue24747
>>> api.PyFile_AsFile(id(f))
2019259400
请记住,对于 fd
和 C 指针,您需要手动确保正确的对象生命周期!
os.fdopen()
返回的类文件对象确实在 .close()
上关闭了描述符
os.dup()
复制描述符PyFile_IncUseCount()
调整相应对象的引用计数。/PyFile_DecUseCount()
.iter(f)
/for l in f
, 内部缓存独立于 stdio
的缓存)关于python - 将 FILE * 传递给 Python/ctypes 中的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33310675/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!