当前位置: 首页 > 面试题库 >

Python和Ctypes:将结构体作为指针传递给函数以获取数据

方英耀
2023-03-14
问题内容

我已经看过其他答案,但似乎无法解决这个问题。我正在尝试在DLL中调用一个函数以与SMBus设备进行通信。此函数采用指向结构的指针,该结构具有一个数组作为字段之一。所以…

在C中:

typedef struct _SMB_REQUEST
{
    unsigned char Address;
    unsigned char Command;
    unsigned char BlockLength;
    unsigned char Data[SMB_MAX_DATA_SIZE];
} SMB_REQUEST;

我想我必须在DLL填充html" target="_blank">数据数组时为Address,Command和BlockLength设置值。需要此结构的函数将其作为指针

SMBUS_API int SmBusReadByte( SMBUS_HANDLE handle, SMB_REQUEST *request );

因此,我已经像这样在Python中设置了结构:

class SMB_REQUEST(ctypes.Structure):
    _fields_ = [("Address", c_char),
            ("Command", c_char),
            ("BlockLength", c_char),
            ("Data", type(create_string_buffer(SMB_MAX_DATA_SIZE))]

注意:我也尝试过ctypes.c_char * SMB_MAX_DATA_SIZE作为数据类型

为了将指向这种结构的指针传递给函数,我尝试如下进行初始化:

data = create_string_buffer(SMB_MAX_DATA_SIZE)
smb_request = SMB_REQUEST('\x53', \x00', 1, data)

这是响应:

TypeError: expected string or Unicode object, c_char_Array_32 found

如果我尝试省略数据数组,如下所示:

smb_request = SMB_REQUEST('\x53', \x00', 1)

不,错误。但是,当我尝试将此传递给函数时:

int_response =  smbus_read_byte(smbus_handle, smb_request))

我得到:

ArgumentError: argument 2: <type 'exceptions.TypeError'>: expected LP_SMB_REQUES
T instance instead of SMB_REQUEST

我尝试过将它作为指针传递:

int_response =  smbus_read_byte(smbus_handle, ctypes.POINTER(smb_request))

我得到:

----> 1
      2
      3
      4
      5

TypeError: must be a ctypes type

这是我设置艺术类型的方法:

smbus_read_byte.argtypes = (ctypes.c_void_p, ctypes.POINTER(SMB_REQUEST))

我已经尝试过投放,但还是没有去。谁能为我阐明一下?

更新:

如果我首先像这样初始化结构:

smb_request = SMB_REQUEST('\xA6', '\x00', chr(1), 'a test string')

然后按参考低音:

int_response =  smbus_receive_byte(smbus_handle, ctypes.byref(smb_request))

我没有错。但是,该函数在成功返回“
0”且失败返回非零时返回-1。检查smb_request.Data的值会返回“测试字符串”,因此此处没有更改。任何关于这里可能发生的事情的建议将不胜感激。

谢谢

更新:

由于我已经询问过一些有关手柄是否正确的信息,因此这是我的使用方法。DLL的头文件声明以下内容:

typedef void *SMBUS_HANDLE;

//
// This function call initializes the SMBus, opens the driver and 
// allocates the resources associated with the SMBus.
// All SMBus API calls are valid 
// after making this call except to re-open the SMBus.
//
SMBUS_API SMBUS_HANDLE OpenSmbus(void);

因此,这就是我在python中执行此操作的方式:

smbus_handle = c_void_p() # NOTE: I have also tried it without this line but same result

open_smbus = CDLL('smbus.dll').OpenSmbus
smbus_handle =  open_smbus()
print 'SMBUS_API SMBUS_HANDLE OpenSmbus(void): ' + str(smbus_handle)

我先调用此命令,然后再调用smbus_read_byte()。我尝试设置,open_smbus.restype = c_void_p()但出现错误:TypeError: restype must be a type, a callable, or None


问题答案:

这是一个工作示例。好像您将错误的类型传递给函数。

测试DLL代码(在Windows上为“ cl / W4 / LD xc”)

#include <stdio.h>

#define SMBUS_API __declspec(dllexport)
#define SMB_MAX_DATA_SIZE 5

typedef void* SMBUS_HANDLE;

typedef struct _SMB_REQUEST
{
    unsigned char Address;
    unsigned char Command;
    unsigned char BlockLength;
    unsigned char Data[SMB_MAX_DATA_SIZE];
} SMB_REQUEST;

SMBUS_API int SmBusReadByte(SMBUS_HANDLE handle,SMB_REQUEST *request)
{
    unsigned char i;
    for(i = 0; i < request->BlockLength; i++)
        request->Data[i] = i;
    return request->BlockLength;
}

SMBUS_API SMBUS_HANDLE OpenSmbus(void)
{
    return (void*)0x12345678;
}

Python代码

from ctypes import *
SMB_MAX_DATA_SIZE = 5
ARRAY5 = c_ubyte * SMB_MAX_DATA_SIZE

class SMB_REQUEST(Structure):
    _fields_ = [
        ("Address", c_ubyte),
        ("Command", c_ubyte),
        ("BlockLength", c_ubyte),
        ("Data", ARRAY5)]

smbus_read_byte = CDLL('x').SmBusReadByte
smbus_read_byte.argtypes = [c_void_p,POINTER(SMB_REQUEST)]
smbus_read_byte.restype = c_int
open_smbus = CDLL('x').OpenSmbus
open_smbus.argtypes = []
open_smbus.restype = c_void_p

handle = open_smbus()
print 'handle = %08Xh' % handle

smb_request = SMB_REQUEST(1,2,5)

print 'returned =',smbus_read_byte(handle,byref(smb_request))
print 'Address =',smb_request.Address
print 'Command =',smb_request.Command
print 'BlockLength =',smb_request.BlockLength
for i,b in enumerate(smb_request.Data):
    print 'Data[%d] = %02Xh' % (i,b)

输出量

handle = 12345678h
returned = 5
Address = 1
Command = 2
BlockLength = 5
Data[0] = 00h
Data[1] = 01h
Data[2] = 02h
Data[3] = 03h
Data[4] = 04h


 类似资料:
  • 问题内容: 我正在尝试使用Python ctypes访问DLL文件中的函数。提供的功能说明如下。 该函数引用DLL中定义的一些变量类型。接下来介绍这些变量 请注意,在提供的头文件之一中定义了“ pichar”,如下所示: 这似乎很简单,但是出于某种原因对我来说却无法解决。 我的理解如下:我向函数传递了三个变量: 1)一个,实际上是一个。有人告诉我python ctypes本质上不支持枚举,因此我将

  • 我正在使用一个第三方库函数,它有大量的位置参数和命名参数。在我的代码中,从多个点使用相同的参数/值调用该函数。 为了便于维护,我不想在代码中多次硬编码几十个相同的参数。我希望有一种方法可以在数据结构中存储它们一次,所以我只需要传递数据结构。按照以下思路: 假设我调用的函数的签名如下: 假设在我的代码中,我想用 for arg1, for arg2 for arg4 (而且我没有使用arg3)。 我

  • C++ 指针 C++ 允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。 下面的实例中,我们传递一个无符号的 long 型指针给函数,并在函数内改变这个值: #include <iostream> #include <ctime> using namespace std; void getSeconds(unsigned long *par); int main () {

  • 我正在尝试编写一个类模板,在内部它使用一个函数(BFGS优化的实现,由环境提供),接口如下: 其中< code>fn和< code>gr是类型的函数指针 和 分别是。我的< code>C 类模板如下所示: 这样,它可以由任何具有两个指定成员函数的类进行实例化,例如: 这可能吗?或者也许有更好的方法来做到这一点 - 将两个成员函数分别作为函数指针传递?(如果目标函数和相应的梯度很简单,那么编写两个函

  • 当我构建这个应用程序时,我得到错误: 我也试过: 这将错误更改为: 下面是调用这个例程的类和我传递的回调函数的示例:

  • 问题内容: 我在C库中有这样的结构。DataFn中的函数指针指向静态函数。 。H 使用objdump,该表仅包含DATAFUNC和gcc的其他内容。 这在C语言中很好,在其中调用fn1就像DATAFUNC.fn1(…,…),但是这样的东西如何包装起来,以便可以在python w / ctypes中调用fn1呢? python示例 结果是 这是相似的,但是没有工厂功能。 问题答案: [Python