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

  • Post author:
  • Post category:python


事情并不像第一眼看到的那样容易.我将发布一个虚拟示例,恰好包含使用.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]\n”, __FILE__, __LINE__, __FUNCTION__)

#define PRINT_MSG_1I(ARG0) printf(” [%s] (%d) – [%s]: ARG0: %d\n”, __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: {:}\n”.format(intf_ptr))

if not intf_ptr:

print(” NULL pointer returned from C\n”)

return

intf = intf_ptr.contents # Dereference the pointer

res = intf.is_valid_int(-2718281)

print(” `is_valid_int` member returned: {:d}\n”.format(res))

res = intf.invalid_int()

print(” `invalid_int` member returned: {:d}\n”.format(res))

res = intf.is_valid_size(3141592)

print(” `is_valid_size` member returned: {:d}\n\n”.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}\n”.format(sys.version, sys.platform))

main()

笔记:

> C部分:

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

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

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

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

> Python部分:

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

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

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

输出:

06002



版权声明:本文为weixin_39627481原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。