我已经定义了一个结构:
Enable Full solution analysis
结构初始化:
class FILE_HANDLE(Structure):
_fields_ = [
("handle_bytes", c_uint),
("handle_type", c_int),
("f_handle", POINTER(c_char))
]
我通过引用它来传递它。
buf = create_string_buffer(f_handle.handle_bytes)
fh = FILE_HANDLE(c_uint(8), c_int(0), buf)
我可以用strace检查调用是否有效,但我无法弄清楚如何访问fh.f_handle的值
fh.f_handle类型为ret = libc.name_to_handle_at(dirfd, pathname, byref(fh), byref(mount_id), flags)
fh.f_handle.contents类型是<ctypes.LP_c_char object at 0x7f1a7ca17560>
但是如果我尝试访问它的值,我会得到一个SIGSEGV。
我如何从f_handle获得8个字节到字符串或数组?
答案 0 :(得分:1)
所有内容实际上都适合你所展示的内容,但如果没有看到你所称的结构和功能的显式C定义,很难看出问题。
这是一个与您展示的内容相关的示例。我推断出C定义应该来自你在Python中声明的内容,但是如果你遇到段错误,很可能你的定义是不同的。
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;
}
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])
dirfd=1 pathname=abc fh->handle_bytes=8 fh->handle_type=0 flags=7
mount_id = 123
fh.f_handle = b'ABCDEFGH'
请注意,由于结构被声明为指向单个字符的指针,因此打印fh.f_handle.contents
只会打印b'A'
。使用切片,我已经指示Python将指针索引到分配的长度。
如果这对您不起作用,请提供Minimal, Complete, and Verifiable example(正如我所知)来准确再现您的错误。
答案 1 :(得分:-1)
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)
将输出
<class 'ctypes.c_char_Array_8'>
<class 'ctypes.LP_c_char'>
您已定义结构以接受指向c_char的指针。因此,当您尝试访问fh.f_handle时,它将期望该值为包含实际单个c_char的地址的内存地址。
但是通过尝试从字符串缓冲区输入c_char * 8,它会将缓冲区的第一部分转换为指针。
Python尝试取消引用您的char [0],这意味着它将查找具有您在char [0]中定义的字符值的内存地址。该内存地址无效,因此您的解释器将发出SIGSEGV信号。
现在创建一个正确处理可变长度缓冲区的类非常困难。一个更简单的选择是将缓冲区作为不透明句柄传递,然后在需要将其转换回char数组时访问它。
示例:
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)