从python ctypes中删除引用的C结构字符串



我无法从pythonctypes访问C代码(dll库(分配的引用结构中的(固定长度(字符串。但是我可以访问和更改int类型。

这是简化的代码。事实上,我正在访问我无法更改的专有dll,因此请将此dll的内容视为已修复。我能够毫无问题地从C代码访问dll结构字符串——这就是我构建这个示例dll的方式,所以它的接口与专有dll的接口相同。

我的假设是错误的,要么是DATA_STRUCT"text">的python声明(列出了各种测试的可能性(,要么是我想要访问字符串的方式-被注释为它们要么只返回对象,要么在windows错误中失败(访问冲突(。

需要注意的是,我使用的是Dev-C++TDM-GCC 4.9.2 64位(应该使用MingW64(和64位Python 3.8.2提供的编译器。使用64位python的原因是专有的dll,它是64位的。Everthing是在Windows(7(下运行的。

dll.h

typedef struct REFERENCE_STRUCT {
int     type ;
void * dataP ;
} REFERENCE_STRUCT ;
typedef struct DATA_STRUCT {
int        number ;
char       text [41] ; // the string is fixed length
} DATA_STRUCT ;
__declspec(dllexport) int test_alloc (REFERENCE_STRUCT *refP) ;
__declspec(dllexport) int test_print (REFERENCE_STRUCT *refP) ;
__declspec(dllexport) int test_free (REFERENCE_STRUCT *refP) ;

maindll.c

#include "dll.h"
#include <windows.h>
#include <string.h>
#include <stdio.h>
__declspec(dllexport) int test_alloc (REFERENCE_STRUCT *refP) {
DATA_STRUCT         *dataP ;
dataP = malloc (sizeof (DATA_STRUCT));
dataP->number = 5 ;
strcpy (dataP->text, "number 1");
refP->type = 40 ;
refP->dataP = ( void *) dataP ;
printf ("DLL - alloc: reference type: %d;  data <%d>; <%s>n", refP->type, dataP->number, dataP->text) ;
return 0;
} ;
__declspec(dllexport) int test_print (REFERENCE_STRUCT *refP) {
DATA_STRUCT         *dataP ;
dataP = (DATA_STRUCT*) refP->dataP ;
printf ("DLL - print: reference type: %d;  data <%d>; <%s>n", refP->type, dataP->number, dataP->text) ;
return 0;
} ;
__declspec(dllexport) int test_free (REFERENCE_STRUCT *refP){
free(refP->dataP) ;
printf ("DLL - freen") ;
return 0;
} ;

script.py

import sys,os, ctypes, ctypes.util, faulthandler
faulthandler.enable()
os.add_dll_directory("D:/path_to_lib/")
mylib_path = ctypes.util.find_library("mydll")
mylib = ctypes.CDLL(mylib_path)
class REFERENCE_STRUCT(ctypes.Structure):
_fields_ = [("type", ctypes.c_int),
("dataP", ctypes.c_void_p)]
class DATA_STRUCT(ctypes.Structure):
_fields_ = [("number", ctypes.c_int),
("text", ctypes.c_char * (41))]    # !!! THIS declaration is correct for C "char       text [41] ;" !!!
("text", ctypes.POINTER(ctypes.c_char * (41)))]    # WHICH declaration is correct for C "char       text [41] ;" ?
#                 ("text", ctypes.POINTER(ctypes.c_char))]           # WHICH declaration is correct for C "char       text [41] ;" ?
#                 ("text", ctypes.c_char_p)]                         # WHICH declaration is correct for C "char       text [41] ;" ?
reference = REFERENCE_STRUCT()
print("test_alloc: ", mylib.test_alloc (ctypes.byref(reference)))
print("reference.type: ", reference.type)
dataP = ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT))
# accessing the number without problem:
print("dataP.contents.number:      ",dataP.contents.number)
print(ctypes.cast(reference.dataP,         
ctypes.POINTER(DATA_STRUCT)).contents.text)
print("test_print: ", mylib.test_print (ctypes.byref(reference)))
dataP.contents.number = 7
ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT)).contents.text = b'num 6'
print("dataP.contents.number:      ",dataP.contents.number)
print(ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT)).contents.text)
print("test_print: ", mylib.test_print (ctypes.byref(reference)))
print("n")
print("test_free: ", mylib.test_free (ctypes.byref(reference))) # freeing the alocated memory

Listing[Python.Docs]:ctypes-Python的外部函数库。

有一些问题:

  1. DATA_STRUCT.text定义(如您所注意到的(。它应该是:("text", ctypes.c_char * 41)

  2. 外部函数的argtypesrestype定义。[SO]中详细介绍的主题:通过ctypes从Python调用的C函数返回错误值(@CristiFati的答案(

  3. 访问成员:ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT)).contents.text(可以将强制转换指针存储在一个额外的变量中,以避免多次执行(写入(它(

最新更新