本文的目的是介绍如何使用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 Ctypes 结构体指针处理(函数参数,函数返回)
- Python ctypes返回函数指针数组
- Python | 使用ctypes访问dll
如何使用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
尝试将它们解释为双精度型。更改ArrayType
为ctypes.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函数返回一个字符串
我是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 结构体指针处理(函数参数,函数返回)
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;
}
使用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返回函数指针数组
我正在使用一个包含单个调用的.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_pfirstfuncptr = my_api(2)
firstfunc = prototype(firstfuncptr)
firstfunc.argtypes[c_int]
firstfunc.restypes = c_inttest = 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 win32Testing 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
我正在尝试访问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搜索路径在一个线程安全的方式通过更新SetDefaultDllDirectories
,AddDllDirectory
和RemoveDllDirectory
。但是这种方法将是最重要的。
在这种情况下,为了简化和与Windows的较旧版本兼容,只需LoadLibraryEx
用flag调用就足够了LOAD_WITH_ALTERED_SEARCH_PATH
。您需要使用绝对路径加载DLL,否则行为是不确定的。为了方便起见,我们可以继承ctypes.CDLL
和ctypes.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 ++函数返回到Python和c++数组作为函数返回值的分享就到这里,谢谢您的阅读,如果想了解更多关于ctypes从c函数返回一个字符串、Python Ctypes 结构体指针处理(函数参数,函数返回)、Python ctypes返回函数指针数组、Python | 使用ctypes访问dll的相关信息,可以在本站进行搜索。
本文标签: