当前位置: 首页 > >

python ctypes 指针 数组 取值_Python ctypes返回一个函数指针数组

发布时间:

事情并不像第一眼看到的那样容易.我将发布一个虚拟示例,恰好包含使用.dlls(.sos)函数的两种方法(如


[Python 3]: ctypes ? A foreign function library for Python中所述).


dll.c:


#include


#if defined(_WIN32)


# define DLL_EXPORT __declspec(dllexport)


# pragma warning(disable: 4477) // !!! Just to avoid having additional code (macro for size_t), do NOT do this !!!


#else


# define DLL_EXPORT


#endif


#define PRINT_MSG_0() printf(" [%s] (%d) - [%s]
", __FILE__, __LINE__, __FUNCTION__)


#define PRINT_MSG_1I(ARG0) printf(" [%s] (%d) - [%s]: ARG0: %d
", __FILE__, __LINE__, __FUNCTION__, ARG0)


static int IsValidInt(int i) {


PRINT_MSG_1I(i);


return -i;


}


static int InvalidInt() {


PRINT_MSG_0();


return 0;


}


static int IsValidSize (size_t i) {


PRINT_MSG_1I(i);


return -i;


}


typedef struct DllInterfaceV2Struct {


int (__cdecl *IsValidIntFuncPtr)(int i);


int (__cdecl *InvalidIntFuncPtr)();


int (__cdecl *IsValidSizeFuncPtr)(size_t i);


} DllInterfaceV2;


static DllInterfaceV2 intfV2 = {IsValidInt, InvalidInt, IsValidSize};


#if defined(__cplusplus)


extern "C" {


#endif


DLL_EXPORT const DllInterfaceV2 *GetInterfaceV2(int version);


#if defined(__cplusplus)


}


#endif


DLL_EXPORT const DllInterfaceV2 *GetInterfaceV2(int version) {


if (version == 2) {


return &intfV2;


} else {


return NULL;


}


}


code.py:


#!/usr/bin/env python3


import sys


import ctypes


DLL_NAME = "test.dll"


DLL_FUNC_NAME = "GetInterfaceV2"


# "Define" the Python counterparts for C stuff in order to be able to use it


IsValidIntFuncPtr = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)


InvalidIntFuncPtr = ctypes.CFUNCTYPE(ctypes.c_int)


IsValidSizeFuncPtr = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_size_t)


class DllInterfaceV2(ctypes.Structure):


_fields_ = [


("is_valid_int", IsValidIntFuncPtr),


("invalid_int", InvalidIntFuncPtr),


("is_valid_size", IsValidSizeFuncPtr)


]


# Now, play with C stuff


def test_interface_ptr(intf_ptr):


print("Testing returned interface: {:}
".format(intf_ptr))


if not intf_ptr:


print(" NULL pointer returned from C
")


return


intf = intf_ptr.contents # Dereference the pointer


res = intf.is_valid_int(-2718281)


print(" `is_valid_int` member returned: {:d}
".format(res))


res = intf.invalid_int()


print(" `invalid_int` member returned: {:d}
".format(res))


res = intf.is_valid_size(3141592)


print(" `is_valid_size` member returned: {:d}

".format(res))


def main():


test_dll = ctypes.CDLL(DLL_NAME)


get_interface_v2_func = getattr(test_dll, DLL_FUNC_NAME) # Or simpler: test_dll.GetInterfaceV2


get_interface_v2_func.argtypes = [ctypes.c_int]


get_interface_v2_func.restype = ctypes.POINTER(DllInterfaceV2)


pintf0 = get_interface_v2_func(0)


test_interface_ptr(pintf0)


pintf2 = get_interface_v2_func(2)


test_interface_ptr(pintf2)


if __name__ == "__main__":


print("Python {:s} on {:s}
".format(sys.version, sys.platform))


main()


笔记:


> C部分:


>我必须添加一些虚拟代码才能测试和说明行为


>虽然你提到它不可修改,但我改变了东西(主要是命名/编码风格,……):


>两个字母的下划线看起来都不好看(至少对我来说)


>(函数,类或任何其他)名称中的“my”(或其任何变体)只会让我的大脑感到震惊


> Python部分:


>正如我在评论中所说,C语言必须在Python中“重复”


>虽然我认为这是一个主要的设计缺陷,但为了使事情尽可能接*问题,我只是遵循它(GetInterfaceV2(V2部分)考虑到它的arg(版本)没有任何意义)


>我的个人意见(虽然没有所有上下文)是(为了确保可伸缩性),该函数应返回一个通用结构,其中包含可由客户端应用程序检查的附加字段(例如版本).


输出:


06002



友情链接: