c - 从 python ctypes 访问引用的 C 结构字符串
问题描述
我无法从 python ctypes访问C 代码(dll 库)分配的引用结构中的(固定长度)字符串。但是我可以访问和更改int类型。
这是简化的代码。实际上,我正在访问无法更改的专有 dll,因此请将此 dll 的内容视为已修复。我可以毫无问题地从 C 代码访问 dll 结构字符串 - 这就是我构造这个示例 dll 的方式,因此它的接口与专有 dll 的接口相同。
我的假设是错误是DATA_STRUCT中“文本”的python 声明(列出了各种测试的可能性),或者我想要访问字符串的方式 - 被注释为它们要么只返回对象,要么在 Windows 错误中失败(访问冲突)。
请注意,我使用的是 Dev-C++ TDM-GCC 4.9.2 64 位(应该使用 MingW64)和 64 位 Python 3.8.2 提供的编译器。使用 64 位 python 的原因是专有 dll,即 64 位。一切都在 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 - free\n") ;
return 0;
} ;
脚本.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
解决方案
清单[Python.Docs]:ctypes - Python 的外部函数库。
有一些问题:
DATA_STRUCT.text定义(如您所见)。它应该是:
("text", ctypes.c_char * 41)
外部函数的argtypes和restype定义。[SO]中详述的主题:通过 ctypes 从 Python 调用的 C 函数返回不正确的值(@CristiFati 的回答)
访问成员:(
ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT)).contents.text
可以将强制转换指针存储在附加变量中以避免多次执行(写入)它)
推荐阅读
- javascript - 在Javascript中的函数之间传递变量?
- matplotlib - matplotlib 中的条件回调函数
- c++ - 从函数返回结构
- github - 移动到子项后如何保持对 github 提交的验证?
- javascript - 如何修复 vmodel 选择的选项 vue js
- r - 具有公式返回的 R 函数具有较大的内存印记
- javascript - 即使用户没有响应 JavaScript 的“confirm()”,我如何才能注销用户?
- lodash - 咖喱 lodash 选择功能无法按预期工作
- elasticsearch - 通过来自另一个索引的 ID 过滤 Elastic Search 索引的快速有效的方法
- mysql - Laravel 8 de 迁移过程中出现外来错误