简体   繁体   English

Python Ctypes - 字符串到 c_char_p 到 c_void_p 并返回

[英]Python Ctypes - String to c_char_p to c_void_p and back

I'm being unable to create certain C data structures in Python using Ctypes and then read them back properly.我无法使用 Ctypes 在 Python 中创建某些 C 数据结构,然后正确读取它们。 Consider the following:考虑以下:

Setup:设置:

from ctypes import Structure, c_void_p, c_char_p, POINTER, cdll, cast

class GSLIST(Structure):
    """GLib's GSList."""
    pass

GSLIST._fields_ = [
    ('data', c_void_p),
    ('next', POINTER(GSLIST))
]

lib = cdll.LoadLibrary('/path/to/mylib.o')

lib.g_slist_prepend.argtypes = [POINTER(GSLIST), c_char_p]
lib.g_slist_prepend.restype = POINTER(GSLIST)

Example:例子:

py_str_in = bytes('hi', 'ascii')

agslist_ptr = POINTER(GSLIST)()  # NULL
agslist_ptr = lib.g_slist_prepend(agslist_ptr, c_char_p(py_str_in))

print(cast(agslist_ptr.contents.data, c_char_p).value.decode())
# 'hi'

The example may be a bit more complicated than it needs to be, but it's been hard to replicate at a smaller scale.这个例子可能比它需要的复杂一点,但很难在较小的规模上复制。

What the example does is to save the "hi" string in the data field of the first element of a GSList (the most common list type in the GLib library).该示例所做的是将“hi”字符串保存在 GSList(GLib 库中最常见的列表类型)的第一个元素的数据字段中。 This field is of type void* so that it can support whatever type.该字段的类型为void* ,因此它可以支持任何类型。 So, first we convert to a c_char_p to make it compatible with void* , and then to read it back we cast() it.因此,首先我们转换为c_char_p以使其与void*兼容,然后将其读回我们cast()它。

The example as shown works as expected.所示示例按预期工作。 It breaks if we do instead:如果我们这样做,它会中断:

agslist_ptr = lib.g_slist_prepend(agslist_ptr, c_char_p(bytes('hi', 'ascii')))

Simply skipping the assignment to the py_str_in variable results in just '' for an output.简单地跳过对py_str_in变量的赋值只会导致''用于输出。

Also, if instead of 'hi' I use any single character, it also works fine.此外,如果我使用任何单个字符而不是'hi' ,它也可以正常工作。

I can't really explain what is going on and the documentation doesn't go into too much depth.我无法真正解释发生了什么,文档也没有深入。 If I had to guess, something with string literals or garbage collection.如果我不得不猜测,那就是字符串文字或垃圾收集。 But it could also be just buggy code.但它也可能只是错误的代码。

Thanks for any insight.感谢您的任何见解。

The 2nd instance that fails is due to c_char_p(bytes('hi', 'ascii') being the only reference to the object. Python doesn't know that C saved that pointer, so after that line executes the object is destroyed and the pointer that C saved is now invalid. Referencing it is undefined behavior.失败的第二个实例是由于c_char_p(bytes('hi', 'ascii')是对该对象的唯一引用。Python 不知道 C 保存了该指针,因此在该行执行后对象被销毁并且C 保存的指针现在无效。引用它是未定义的行为。

In the 1st case the py_str_in reference still exists so the pointer C saved is still valid.在第一种情况下, py_str_in引用仍然存在,因此保存的指针 C 仍然有效。

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

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