从python ctypes中获取引用的C结构字符串

问题描述 投票:0回答:1

我无法从python中访问 c类型绳子 由C代码(dll库)分配的引用结构。但是 我可以访问和更改的类型。

这是简化后的代码,实际上我访问的是我无法改变的专有dll,因此请把这个dll的内容当作固定的。实际上我访问的是专有的dll,我无法改变,所以请把这个dll的内容当作固定的内容,我能够从C代码中访问dll结构字符串,没有问题--这是我构造这个例子dll的方式,所以它的接口和专有dll的接口是一样的。

我的假设是,错误的是要么python声明的 "文本"DATA_STRUCT (各种测试过的可能性都列出来了),或者我想访问字符串的方式--都被注释了,因为它们要么只返回对象,要么在windows下失败(访问违规)。

需要说明的是,我使用的是Dev-C++提供的编译器TDM-GCC 4.9.2 64位(应该使用MingW64)和64位Python 3.8.2.使用64位Python的原因是专有的dll,是64位的。

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
c string pointers struct ctypes
1个回答
0
投票

列表 [Python 3.Docs]: ctypes - 一个Python的外来函数库。.

有一些问题。

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

  2. argtypes复型 外来函数的定义。主题详见 [so]: 通过ctypes从Python调用C函数,返回不正确的值(@CristiFati的答案)

  3. 访问成员。ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT)).contents.text (可将投掷指针存储在一个附加变量中,以避免多次做(写)它)

© www.soinside.com 2019 - 2024. All rights reserved.