简体   繁体   English

如何访问 ctypes.LP_c_char 指针的值?

[英]How to access the value of a ctypes.LP_c_char pointer?

I have defined a struct :我定义了一个结构:

class FILE_HANDLE(Structure):
_fields_ = [
    ("handle_bytes", c_uint),
    ("handle_type", c_int),
    ("f_handle", POINTER(c_char))
]

The struct is initialised :结构被初始化:

buf = create_string_buffer(f_handle.handle_bytes)
fh = FILE_HANDLE(c_uint(8), c_int(0), buf)

I am passing it by reference to a function that populates it.我通过引用填充它的函数来传递它。

ret = libc.name_to_handle_at(dirfd, pathname, byref(fh), byref(mount_id), flags)

I can check with strace that the call works, but I have not been able to figure out how to access the value of fh.f_handle我可以使用 strace 检查该调用是否有效,但我无法弄清楚如何访问 fh.f_handle 的值

fh.f_handle type is <ctypes.LP_c_char object at 0x7f1a7ca17560> fh.f_handle 类型是<ctypes.LP_c_char object at 0x7f1a7ca17560>
fh.f_handle.contents type is <ctypes.LP_c_char object at 0x7f1a7ca17560> but I get a SIGSEGV if I try to access its value. fh.f_handle.contents 类型是<ctypes.LP_c_char object at 0x7f1a7ca17560>但如果我尝试访问它的值,我会得到一个 SIGSEGV。
How could I get 8 bytes from f_handle into a string or array ?如何从 f_handle 获取 8 个字节到字符串或数组中?

Everything actually looks right for what you've shown, but without seeing the explicit C definition of the structure and function you are calling it is difficult to see the problem.一切实际上看起来都适合您所展示的内容,但是如果没有看到您正在调用的结构和函数的显式 C 定义,就很难看出问题所在。

Here's an example that works with what you have shown.这是一个适用于您所展示内容的示例。 I inferred what the C definitions should be from what you have declared in Python, but most likely your definition is different if you get a segfault.我从您在 Python 中声明的内容推断出 C 定义应该是什么,但是如果您遇到段错误,您的定义很可能会有所不同。

C Code (Windows) C 代码 (Windows)

struct FILE_HANDLE
{
    unsigned int handle_bytes;
    int handle_type;
    char* f_handle;
};

__declspec(dllexport) int name_to_handle_at(int dirfd, char* pathname, struct FILE_HANDLE* fh, int* mount_id, int flags)
{
    unsigned int i;
    printf("dirfd=%d pathname=%s fh->handle_bytes=%u fh->handle_type=%d flags=%d\n", dirfd, pathname, fh->handle_bytes, fh->handle_type, flags);
    for(i = 0; i < fh->handle_bytes; ++i)
        fh->f_handle[i] = 'A' + i;
    *mount_id = 123;
    return 1;
}

Python code (Works in Python 2 and 3): Python 代码(适用于 Python 2 和 3):

from __future__ import print_function
from ctypes import *

class FILE_HANDLE(Structure):
    _fields_ = [("handle_bytes", c_uint),
                ("handle_type", c_int),
                ("f_handle", POINTER(c_char))]

buf = create_string_buffer(8);
fh = FILE_HANDLE(8,0,buf)
libc = CDLL('test.dll')
mount_id = c_int(0)
ret = libc.name_to_handle_at(1,b'abc',byref(fh),byref(mount_id),7)
print('mount_id =',mount_id.value)
print('fh.f_handle =',fh.f_handle[:fh.handle_bytes])

Output输出

dirfd=1 pathname=abc fh->handle_bytes=8 fh->handle_type=0 flags=7
mount_id = 123
fh.f_handle = b'ABCDEFGH'

Note that since the structure is declared as a pointer to a single character, printing fh.f_handle.contents would only print b'A' .请注意,由于该结构被声明为指向单个字符的指针,因此打印fh.f_handle.contents只会打印b'A' Using slicing, I've instructed Python to index the pointer up to the length allocated.使用切片,我已经指示 Python 将指针索引到分配的长度。

If this doesn't work for you, provide a Minimal, Complete, and Verifiable example (as I have) to reproduce your error exactly.如果这对您不起作用,请提供一个最小、完整和可验证的示例(如我所见)以准确重现您的错误。

fh.f_handle is shown as LP_c_char because you defined the struct that way. fh.f_handle 显示为 LP_c_char 因为您以这种方式定义了结构。

buf = create_string_buffer(8)
print type(buf)
fh = FILE_HANDLE(c_uint(8), c_int(0), buf)
print type(fh.f_handle)

Will output会输出

<class 'ctypes.c_char_Array_8'>
<class 'ctypes.LP_c_char'>

You have defined your struct to accept a pointer to a c_char.您已将结构定义为接受指向 c_char 的指针。 So when you try to access fh.f_handle it will expect the value to be a memory address containing the address to the actual single c_char.因此,当您尝试访问 fh.f_handle 时,它​​会期望该值是包含实际单个 c_char 的地址的内存地址。

But by trying to input a c_char * 8 from the string buffer it will convert the first part of your buffer to a pointer.但是通过尝试从字符串缓冲区输入 c_char * 8 ,它会将缓冲区的第一部分转换为指针。

Python tries to dereference your char[0] which means that it will look for a memory address with the value of the character you have defined in char[0]. Python 会尝试取消对您的 char[0] 的引用,这意味着它将使用您在 char[0] 中定义的字符的值来查找内存地址。 That memory address is not valid, so your interpreter will signal a SIGSEGV.该内存地址无效,因此您的解释器将发出 SIGSEGV 信号。

Now to create a class which properly handles a variable length buffer is quite difficult.现在创建一个正确处理可变长度缓冲区的类是相当困难的。 An easier option is to pass the buffer as an opaque handle, to access it afterwards you need to cast it back to a char array.一个更简单的选择是将缓冲区作为一个不透明的句柄传递,之后访问它你需要将它转换回一个字符数组。

Example:例子:

class FILE_HANDLE(Structure):
    _fields_ = [
            ("handle_bytes", c_uint),
            ("handle_type", c_int),
            ("f_handle", c_void_p)
        ]

buf = create_string_buffer(8)
buf = cast(buf, c_void_p)
fh = FILE_HANDLE(c_uint(8), c_int(0), buf)
f_handle_value = (c_char * fh.handle_bytes).from_address(fh.f_handle) 

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

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