GVKun编程网logo

如何使用ctypes将数组从C ++函数返回到Python(c++数组作为函数返回值)

9

本文的目的是介绍如何使用ctypes将数组从C++函数返回到Python的详细情况,特别关注c++数组作为函数返回值的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解如

本文的目的是介绍如何使用ctypes将数组从C ++函数返回到Python的详细情况,特别关注c++数组作为函数返回值的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解如何使用ctypes将数组从C ++函数返回到Python的机会,同时也不会遗漏关于ctypes从c函数返回一个字符串、Python Ctypes 结构体指针处理(函数参数,函数返回)、Python ctypes返回函数指针数组、Python | 使用ctypes访问dll的知识。

本文目录一览:

如何使用ctypes将数组从C ++函数返回到Python(c++数组作为函数返回值)

如何使用ctypes将数组从C ++函数返回到Python(c++数组作为函数返回值)

我正在使用ctypes在Python中实现C 函数。C函数应返回一个指向数组的指针。不幸的是,我还没有弄清楚如何在Python中访问数组。我尝试了numpy.frombuffer,但是没有成功。它只是返回一个任意数字的数组。显然我没有正确使用它。这是一个简单的示例,数组大小为10:

function.cpp的内容:

extern "C" int* function(){int* information = new int[10];for(int k=0;k<10;k++){    information[k] = k;}return information;}

wrapper.py的内容:

import ctypesimport numpy as npoutput = ctypes.CDLL(''./library.so'').function()ArrayType = ctypes.c_double*10array_pointer = ctypes.cast(output, ctypes.POINTER(ArrayType))print np.frombuffer(array_pointer.contents)

要编译我正在使用的C ++文件:

g++ -c -fPIC function.cpp -o function.og++ -shared -Wl,-soname,library.so -o library.so function.o

您对在Python中访问数组值有什么建议?

答案1

小编典典

function.cpp返回一个int数组,同时wrapper.py尝试将它们解释为双精度型。更改ArrayTypectypes.c_int* 10,它应该起作用。


仅使用np.ctypeslib而不是frombuffer自己可能更容易。这看起来应该像

import ctypesfrom numpy.ctypeslib import ndpointerlib = ctypes.CDLL(''./library.so'')lib.function.restype = ndpointer(dtype=ctypes.c_int, shape=(10,))res = lib.function()

ctypes从c函数返回一个字符串

ctypes从c函数返回一个字符串

我是Python的资深人士,但对C的涉猎还很少。半天没在网上找到对我有用的任何东西之后,我想我会在这里问问题并获得所需的帮助。

我想做的是编写一个简单的C函数,该函数接受一个字符串并返回另一个字符串。我打算将此功能绑定到多种语言(Java,Obj-C,Python等)中,所以我认为它必须是纯C语言?

到目前为止,这就是我所拥有的。请注意,尝试在Python中检索值时遇到段错误。

你好ç

#include <stdlib.h>#include <stdio.h>#include <string.h>const char* hello(char* name) {    static char greeting[100] = "Hello, ";    strcat(greeting, name);    strcat(greeting, "!\n");    printf("%s\n", greeting);    return greeting;}

main.py

import ctypeshello = ctypes.cdll.LoadLibrary(''./hello.so'')name = "Frank"c_name = ctypes.c_char_p(name)foo = hello.hello(c_name)print c_name.value # this comes back fineprint ctypes.c_char_p(foo).value # segfault

我已经读到段错误是由C释放最初为返回的字符串分配的内存引起的。也许我只是在吠错一棵树?

完成我想要的东西的正确方法是什么?

答案1

小编典典

在hello.c中,您将返回一个本地数组。您必须返回一个指向数组的指针,该数组必须使用malloc动态分配。

char* hello(char* name){     char hello[] = "Hello ";    char excla[] = "!\n";    char *greeting = malloc ( sizeof(char) * ( strlen(name) + strlen(hello) + strlen(excla) + 1 ) );    if( greeting == NULL) exit(1);    strcpy( greeting , hello);    strcat(greeting, name);    strcat(greeting, excla);    return greeting;}

Python Ctypes 结构体指针处理(函数参数,函数返回)

Python Ctypes 结构体指针处理(函数参数,函数返回)

C函数需要传递结构体指针是常事,但是和Python交互就有点麻烦事了,经过研究也可以了。

<结构体指针作为函数参数>

来看下C测试例子:

#include <stdio.h>
typedef struct StructPointerTest* StructPointer;
struct StructPointerTest{
        int x;
        int y;
};
void test(StructPointer p) {
        p->x = 101;
        p->y = 201;
}


这里test里面需要传入结构体指针,函数中的实现很简单,就是改变x 和 y 的值这个函数将被python调用。

使用Python调用时,需要模拟申明个结构体(class):

from ctypes import *
class StructPointerTest(Structure): 
    _fields_ =[(''x'', c_int),
               (''y'', c_int)]

Usage:

##Structure Pointer Operation
SPTobj = pointer(StructPointerTest(1, 2))
print SPTobj
print SPTobj.contents.x 
print SPTobj.contents.y

<函数返回结构体指针>

C函数测试例子改成如下:

StructPointer test() {
        StructPointer p = (StructPointer)malloc(sizeof(struct StructPointerTest));
        p->x = 101;
        p->y = 201;
        return p;
}


Python程序处理如下:

from ctypes import *
class StructPointer(Structure):
        pass

StructPointer._fields_=[(''x'', c_int),
                        (''y'', c_int),
                        (''next'', POINTER(StructPointer))]


lib = cdll.LoadLibrary(''./StructPointer.so'')
lib.test.restype = POINTER(StructPointer)

p = lib.test()
print p.contents.x

关于resttype可以参见 Tutorial :  By default functions are assumed to return the C int type. Other return types can be specified by setting the restype attribute of the function object.



原文链接: http://blog.csdn.net/crazyjixiang/article/details/6832920

Python ctypes返回函数指针数组

Python ctypes返回函数指针数组

我正在使用一个包含单个调用的.dll,该调用返回一个函数指针数组。GetMyApi()返回指向结构的指针,该结构是函数指针的数组。函数本身具有不同的单独输入和输出。到目前为止我尝试过的是:

我无法轻易更改的C代码:

  • C中的代码:

    typedef struct My_Api_V2

    {
    int (__cdecl IsValidInt)(int i);
    int (__cdecl
    InvalidInt)();
    int (__cdecl *IsValidSize)(size_t i);
    } my_Api_V2;

    const my_Api_V2* GetMyApi(int version); // This function is accessed from DLL

  • Python的努力:

    from ctypes import *

    my_dll = cdll.LoadLibrary(path_to_my_dll)
    my_api = my_dll.GetMyApi
    my_api.argtypes[c_int] #version number
    my_api.restypes = c_void_p

    firstfuncptr = my_api(2)
    firstfunc = prototype(firstfuncptr)
    firstfunc.argtypes[c_int]
    firstfunc.restypes = c_int

    test = firstfunc(23)

此时,我只是想让功能列表中的第一个功能恢复工作。任何帮助我指出更好方向的帮助都将受到赞赏。

答案1

小编典典

事情并不像人们想象的在1个那样容易ST一目了然。我将发布一个虚拟示例,该示例恰好包含使用 .dll s( .so
s)中的函数的2种方式(如[Python 3.Docs]中所述:ctypes-
Python的外部函数库)。

dll00.c

#include <stdio.h>#if defined(_WIN32)#  define DLL00_EXPORT __declspec(dllexport)#  pragma warning(disable: 4477)  // !!! Just to avoid having additional code (macro for size_t), do NOT do this !!!#else#  define DLL00_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" {#endifDLL00_EXPORT const DllInterfaceV2 *GetInterfaceV2(int version);#if defined(__cplusplus)}#endifDLL_EXPORT const DllInterfaceV2 *GetInterfaceV2(int version) {    if (version == 2) {        return &intfV2;    } else {        return NULL;    }}

code00.py

#!/usr/bin/env python3import sysimport ctypesDLL_NAME = "test00.dll"DLL_FUNC_NAME = "GetInterfaceV2"# "Define" the Python counterparts for C stuff in order to be able to use itIsValidIntFuncPtr = 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 stuffdef 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 部分:

    • 正如我在评论中所述,必须在 Python中 “复制” C 内容 __

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

    • 我个人的观点(尽管没有所有上下文)是(为了确保可伸缩性),该函数应返回通用结构,并带有一个可由客户端应用程序检查的附加字段(例如 version )。

输出

(py35x64_test)

e:\Work\Dev\StackOverflow\q051507196>”c:\Install\x86\Microsoft\Visual Studio
Community\2015\vc\vcvarsall.bat” x64

(py35x64_test) e:\Work\Dev\StackOverflow\q051507196>dir /bcode00.pydll00.c(py35x64_test) e:\Work\Dev\StackOverflow\q051507196>cl /nologo dll00.c

/link /DLL /OUT:test00.dll
dll00.c
Creating library test00.lib and object test00.exp

(py35x64_test) e:\Work\Dev\StackOverflow\q051507196>dir /bcode00.pydll00.cdll00.objtest00.dlltest00.exptest00.lib(py35x64_test)

e:\Work\Dev\StackOverflow\q051507196>”e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe”
code00.py
Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit
(AMD64)] on win32

Testing returned interface: <__main__.LP_DllInterfaceV2 object at

0x00000219984EBAC8>

   NULL pointer returned from CTesting returned interface: <__main__.LP_DllInterfaceV2 object at

0x00000219984EBB48>

        [dll00.c] (16) - [IsValidInt]:  ARG0: -2718281    `is_valid_int` member returned: 2718281        [dll00.c] (22) - [InvalidInt]    `invalid_int` member returned: 0        [dll00.c] (28) - [IsValidSize]:  ARG0: 3141592    `is_valid_size` member returned: -3141592

Python | 使用ctypes访问dll

Python | 使用ctypes访问dll

我正在尝试访问Firefox Web浏览器随附的dll( nss3.dll
)中的某些功能。为了处理此任务,我在Python中使用了ctypes。问题在于它在将dll加载到内存中的初始点失败。

这是我必须要做的代码片段。

>>> from ctypes import *>>> windll.LoadLibrary("E:\\nss3.dll")

我得到的例外是

Traceback (most recent call last):  File "<pyshell#2>", line 1, in <module>    windll.LoadLibrary("E:\\nss3.dll")  File "C:\Python26\lib\ctypes\__init__.py", line 431, in LoadLibrary    return self._dlltype(name)  File "C:\Python26\lib\ctypes\__init__.py", line 353, in __init__    self._handle = _dlopen(self._name, mode)WindowsError: [Error 126] The specified module could not be found

我还尝试从Firefox安装路径加载它,假设可能存在依赖性。

>>> windll.LoadLibrary("F:\\Softwares\\Mozilla Firefox\\nss3.dll")

但我遇到了与上述相同的异常。

谢谢。

答案1

小编典典

nss3.dll链接到以下DLL,它们都位于Firefox目录中:nssutil3.dll,plc4.dll,plds4.dll,nspr4.dll和mozcrt19.dll。系统库加载程序在进程的DLL搜索路径中查找这些文件,这些路径包括应用程序目录,系统目录,当前目录以及PATH环境变量中列出的每个目录。

最简单的解决方案是将当前目录更改为DLL
Firefox目录。但是,这不是线程安全的,因此我一般不会依赖它。另一个选择是将Firefox目录附加到PATH环境变量,这是我在该答案的原始版本中建议的内容。但是,这并不比修改当前目录好多少。

(与更新KB2533623 NT
6.0或更高版本)较新版本的Windows让DLL搜索路径在一个线程安全的方式通过更新SetDefaultDllDirectoriesAddDllDirectoryRemoveDllDirectory。但是这种方法将是最重要的。

在这种情况下,为了简化和与Windows的较旧版本兼容,只需LoadLibraryEx用flag调用就足够了LOAD_WITH_ALTERED_SEARCH_PATH。您需要使用绝对路径加载DLL,否则行为是不确定的。为了方便起见,我们可以继承ctypes.CDLLctypes.WinDLL调用LoadLibraryEx而不是LoadLibrary

import osimport ctypesif os.name == ''nt'':    from ctypes import wintypes    kernel32 = ctypes.WinDLL(''kernel32'', use_last_error=True)    def check_bool(result, func, args):        if not result:            raise ctypes.WinError(ctypes.get_last_error())        return args    kernel32.LoadLibraryExW.errcheck = check_bool    kernel32.LoadLibraryExW.restype = wintypes.HMODULE    kernel32.LoadLibraryExW.argtypes = (wintypes.LPCWSTR,                                        wintypes.HANDLE,                                        wintypes.DWORD)class CDLLEx(ctypes.CDLL):    def __init__(self, name, mode=0, handle=None,                  use_errno=True, use_last_error=False):        if os.name == ''nt'' and handle is None:            handle = kernel32.LoadLibraryExW(name, None, mode)        super(CDLLEx, self).__init__(name, mode, handle,                                     use_errno, use_last_error)class WinDLLEx(ctypes.WinDLL):    def __init__(self, name, mode=0, handle=None,                  use_errno=False, use_last_error=True):        if os.name == ''nt'' and handle is None:            handle = kernel32.LoadLibraryExW(name, None, mode)        super(WinDLLEx, self).__init__(name, mode, handle,                                       use_errno, use_last_error)

这是所有可用的LoadLibraryEx标志:

DONT_RESOLVE_DLL_REFERENCES         = 0x00000001LOAD_LIBRARY_AS_DATAFILE            = 0x00000002LOAD_WITH_ALTERED_SEARCH_PATH       = 0x00000008LOAD_IGNORE_CODE_AUTHZ_LEVEL        = 0x00000010  # NT 6.1LOAD_LIBRARY_AS_IMAGE_RESOURCE      = 0x00000020  # NT 6.0LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE  = 0x00000040  # NT 6.0# These cannot be combined with LOAD_WITH_ALTERED_SEARCH_PATH.# Install update KB2533623 for NT 6.0 & 6.1.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR    = 0x00000100LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200LOAD_LIBRARY_SEARCH_USER_DIRS       = 0x00000400LOAD_LIBRARY_SEARCH_SYSTEM32        = 0x00000800LOAD_LIBRARY_SEARCH_DEFAULT_DIRS    = 0x00001000

例如:

firefox_path = r''F:\Softwares\Mozilla Firefox''nss3 = CDLLEx(os.path.join(firefox_path, ''nss3.dll''),               LOAD_WITH_ALTERED_SEARCH_PATH)nss3.NSS_GetVersion.restype = c_char_p>>> nss3.NSS_GetVersion()                 ''3.13.5.0 Basic ECC''

我们今天的关于如何使用ctypes将数组从C ++函数返回到Pythonc++数组作为函数返回值的分享就到这里,谢谢您的阅读,如果想了解更多关于ctypes从c函数返回一个字符串、Python Ctypes 结构体指针处理(函数参数,函数返回)、Python ctypes返回函数指针数组、Python | 使用ctypes访问dll的相关信息,可以在本站进行搜索。

本文标签: