简体   繁体   English

将指向连续数据的指针从 Python 传递到 C 的最简单方法

[英]The simplest way to pass pointer to contiguous data from Python to C

I am using ctypes to call function in C .我正在使用ctypes在 C 中调用C Function expects pointer to the first element of the contiguous data and number of data. Function 需要指向连续数据的第一个元素和数据数量的指针。

One thing that works is something like that一件事是这样的

a=15 # a could be any number
temp = numpy.array([a]*14, dtype=numpy.int8)
c_function(temp.ctypes.data_as(ctypes.c_void_p), 14)

This is really cumbersome, requires both numpy and ctypes .这真的很麻烦,需要numpyctypes Is there any other more simple way that works both in Python2 and Python3 (AFAIK bytes([a]*14) works but only for Python3)有没有其他更简单的方法在 Python2 和 Python3 中都有效(AFAIK bytes([a]*14)有效,但仅适用于 Python3)

EDIT: More interestingly this also works (!)编辑:更有趣的是,这也有效(!)

a=15 # a could be any number
temp = chr(a)*14
c_function(temp, 14)

There were suggestions in other threads that one could pass something pointer to the first element of the contiguous data, like here Passing memoryview to C function , but I was just unable to make this work.其他线程中有人建议可以将指针传递给连续数据的第一个元素,例如Passing memoryview to C function ,但我无法完成这项工作。

Preliminaries预赛

Python does not have pointers. Python 没有指针。 You cannot create a pointer in Python, though Python variables act in some ways like pointers.您不能在 Python 中创建指针,尽管 Python 变量在某些方面类似于指针。 You can create Python objects that represent lower-level pointers, but what you actually seem to want is to feed your C function a pointer to Python-managed data, which is an altogether different thing.您可以创建代表较低级别指针的 Python 对象,但您实际上似乎想要的是为您的 C function 提供一个完全不同的指针,它是一个指向 Python 管理的数据的指针。

What ctypes does for you ctypes 为您做什么

You seem to have settled on using ctypes for the actual function call, so the general question expressed in the question title is a little overbroad for what you actually want to know.您似乎已经决定将 ctypes 用于实际的 function 调用,因此问题标题中表达的一般问题对于您真正想知道的内容来说有点过于宽泛。 The real question seems to be more like "How do I get ctypes to pass a C pointer to Python-managed data to a C function?"真正的问题似乎更像是“我如何让 ctypes 将指向 Python 管理数据的 C 指针传递给 C function?”

According to the ctypes Python 2 docs , in Python 2,根据ctypes Python 2 文档,在 Python 2 中,

None , integers, longs, byte strings and unicode strings are the only native Python objects that can directly be used as parameters in these function calls. None 、整数、长整数、字节字符串和 unicode 字符串是唯一可以在这些 function 调用中直接用作参数的本机 Python 对象。 None is passed as a C NULL pointer, byte strings and unicode strings are passed as pointer to the memory block that contains their data ( char * or wchar_t * ). None is passed as a C NULL pointer, byte strings and unicode strings are passed as pointer to the memory block that contains their data ( char * or wchar_t * ). [...] [...]

(emphasis added). (强调补充)。

It's more or less the same list in Python 3 ... Python 3 中的列表或多或少相同...

None , integers, bytes objects and (unicode) strings None ,整数,字节对象和(unicode)字符串

... with the same semantics. ...具有相同的语义。

Note well that ctypes takes care of the conversion from Python object to corresponding C representation -- nowhere does Python code handle C pointers per se , nor even direct representations of them. Note well that ctypes takes care of the conversion from Python object to corresponding C representation -- nowhere does Python code handle C pointers per se , nor even direct representations of them.

Relevant C details相关C详情

In many C implementations, all object pointer types have the same representation and can be used semi-interchangeably, but pointers of type char * are guaranteed by the standard to have the same size and representation as pointers of type void * .在许多 C 实现中,所有 object 指针类型都具有相同的表示形式,并且可以半互换使用,但标准保证char *类型的指针与void *类型的指针具有相同的大小和表示形式。 These two pointer types are guranteed to be interchangeable as function parameters and return values, among other things.这两种指针类型保证可以作为 function 参数和返回值等互换。

Synthesis合成

How convenient!多么方便! It is acceptable to call your C function with a first argument of type char * when the function declares that parameter to be of type void * , and that is exactly what ctypes will arrange for you when the Python argument is a byte string (Python 2) or a bytes object (Python 3). It is acceptable to call your C function with a first argument of type char * when the function declares that parameter to be of type void * , and that is exactly what ctypes will arrange for you when the Python argument is a byte string (Python 2 ) 或字节 object (Python 3)。 The C function will receive a pointer to the object's data, not to the object itself. C function 将接收指向对象数据的指针,而不是指向 object 本身的指针。 This provides a simpler and better way forward than going through numpy or a similar package, and it is basically the approach that you appended to your question.与通过 numpy 或类似的 package 相比,这提供了一种更简单、更好的方法,它基本上是您附加到问题的方法。 Thus, supposing that c_function identifies a ctypes-wrapped C function, you could do this (python3):因此,假设c_function标识一个 ctypes 包装的 C function,您可以这样做(python3):

len = 15
c_function(b'0' * len, len)

Of course, you can also create a variable for the object and pass that, instead, which would allow you to afterward see whatever the C function has done with the contents of the object. Of course, you can also create a variable for the object and pass that, instead, which would allow you to afterward see whatever the C function has done with the contents of the object.

Do note, however, that但是请注意,

  1. Byte strings and bytes objects are immutable as far as Python is concerned.就 Python 而言,字节字符串和字节对象是不可变的。 You can get yourself in trouble if you use a C function to change the contents of a bytes object that other Python code assumes will never change. You can get yourself in trouble if you use a C function to change the contents of a bytes object that other Python code assumes will never change.

  2. The C side cannot determine the size of the data from a pointer to it. C端无法从指向它的指针确定数据的大小。 That is presumably the purpose of the second parameter.这大概是第二个参数的目的。 If you tell the function that the object is larger than it really is, and the function relies on that to try to modify bytes past the end of the actual data, then you will have difficult to debug trouble, from corruption of other data to memory leaks. If you tell the function that the object is larger than it really is, and the function relies on that to try to modify bytes past the end of the actual data, then you will have difficult to debug trouble, from corruption of other data to memory泄漏。 If you're lucky, your program will crash.如果你幸运的话,你的程序会崩溃。

  3. It depends on what Python implementation you use, but typically the elements of a Unicode string are larger than one byte each.这取决于您使用的 Python 实现,但通常 Unicode 字符串的元素每个都大于一个字节。 Save yourself some trouble and use byte strings / bytes instead.为自己省点麻烦,改用字节字符串/字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM