Python ctypes не работает со структурами - PullRequest
4 голосов
/ 09 июля 2019

Мне нужно использовать код из LabVIEW в Python. Код LabVIEW используется как DLL. Итак, я использую библиотеку ctypes в Python. В одном случае мне нужно передать cluster s из Python в LabVIEW. У меня проблемы с прохождением кластеров.

Проблема заключается в особом порядке расположения элементов внутри кластера LabVIEW (я знаю, что кластеры строго следуют порядку). Мой кластер имеет значение double и integer array. Когда double является первым элементом в кластере, все работает хорошо. Но когда массив установлен в качестве первого элемента и удваивается в качестве второго элемента, все не работает вообще. Я использую LabVIEW 2015 (32-разрядная версия) и Python 3 (32-разрядная версия).

Я подозреваю, что причиной проблемы является ctypes. Потому что одна и та же DLL работает, как и ожидалось, в C и в LabVIEW. Я также попытался использовать DLL в LabVIEW, которая работает нормально.

Я сузил эту проблему до следующего примера. DLL в этом примере имеет 2 функции. Каждая функция использует кластер. Func1 использует cluster1, то есть array, за которым следует double. В то время как Func2 использует cluster, то есть double, за которым следует array. Обе эти функции получают cluster в качестве входных данных и просто возвращают значение double (как оно есть из входного кластера) в качестве выходных.

Найдите эту информацию в заголовочном файле.

typedef struct {
    int32_t dimSize;
    uint64_t elt[1];
} Uint64ArrayBase;
typedef Uint64ArrayBase **Uint64Array;
typedef struct {
    double Double;
    Uint64Array _1DArray;
} Cluster;
typedef struct {
    Uint64Array _1DArray;
    double Double;
} Cluster1;

/*!
 * Func2
 */
double __cdecl Func2(Cluster *Double1DArrayCluster);
/*!
 * Func1
 */
double __cdecl Func1(Cluster1 *_1DArrayDoubleCluster);

MgErr __cdecl LVDLLStatus(char *errStr, int errStrLen, void *module);

/*
* Memory Allocation/Resize/Deallocation APIs for type 'Uint64Array'
*/
Uint64Array __cdecl AllocateUint64Array (int32 elmtCount);
MgErr __cdecl ResizeUint64Array (Uint64Array *hdlPtr, int32 elmtCount);
MgErr __cdecl DeAllocateUint64Array (Uint64Array *hdlPtr);

Это мой код Python.

from ctypes import *

lib = cdll.LoadLibrary("DLL.dll")
dbl = 45.54
elt_count = 5

class Uint64ArrayBase(Structure):
    _fields_ = [
        ("dimSize", c_int32),
        ("elt", c_uint64 * elt_count)
    ]

class Cluster(Structure):
    _fields_ = [
        ("Double", c_double),
        ("_1DArray", POINTER(POINTER(Uint64ArrayBase)))
    ]

class Cluster1(Structure):
    _fields_ = [
        ("_1DArray", POINTER(POINTER(Uint64ArrayBase))),
        ("Double", c_double)
    ]

Uint64Array = POINTER(POINTER(Uint64ArrayBase))

# Use the given API to allocate array
lib.AllocateUint64Array.restype = Uint64Array
lib.AllocateUint64Array.argtypes = [c_int32]
uintarr_h = lib.AllocateUint64Array(c_int32(elt_count))

# Populate the elts of the array
for i in range(elt_count):
    uintarr_h.contents.contents.elt[i] = c_uint64(i)

# Create cluster instances
dbl_arr_cluster = Cluster(c_double(dbl), uintarr_h)
arr_dbl_cluster = Cluster1(uintarr_h, c_double(dbl))

# Print the array for Debugging
print("Array from arr_dbl_cluster:", end=" ")
for i in range(arr_dbl_cluster._1DArray.contents.contents.dimSize):
    print(arr_dbl_cluster._1DArray.contents.contents.elt[i], end=", ")
print()

print("Array from dbl_arr_cluster:", end=" ")
for i in range(dbl_arr_cluster._1DArray.contents.contents.dimSize):
    print(dbl_arr_cluster._1DArray.contents.contents.elt[i], end=", ")
print()

print("Double from arr_dbl_cluster:", arr_dbl_cluster.Double)
print("Double from dbl_arr_cluster:", dbl_arr_cluster.Double)

# Test the funcs
lib.Func1.restype = c_double
lib.Func1.argtypes = [POINTER(Cluster1)]
lib.Func2.restype = c_double
lib.Func2.argtypes = [POINTER(Cluster)]

print()

result = lib.Func1(byref(arr_dbl_cluster))
print("Double output from DLL function cluster{Array, DBL}:", result)
result_1 = lib.Func2(byref(dbl_arr_cluster))
print("Double output from DLL function cluster{DBL, Array}:", result_1)

Также код C.

#include<stdio.h>
#include "DLL.h"

int main() {
    double dbl = 45.54, result, result1;
    int32 eltCount = 5, i;

    // Use the API to allocate array
    Uint64Array uia = AllocateUint64Array(eltCount);

    // Populate the elts of the array
    for (i = 0; i < (*uia)->dimSize; i++) {
        (*uia)->elt[i] = (int)i;
    }

    // Create cluster instances
    Cluster cluster = { dbl, uia };
    Cluster1 cluster1 = { uia, dbl };

    // Print for Debugging
    printf("\nArray from cluster1{Array, DBL}: ");
    for (i = 0; i < (*cluster1._1DArray)->dimSize; i++) {
        printf("%llu, ", (*cluster1._1DArray)->elt[i]);
    }
    printf("\nArray from cluster{DBL, Array}: ");
    for (i = 0; i < (*cluster._1DArray)->dimSize; i++) {
        printf("%llu, ", (*cluster._1DArray)->elt[i]);
    }

    printf("\nDouble from cluster1{Array, DBL}: %lf", cluster1.Double);
    printf("\nDouble from cluster{DBL, Array}: %lf", cluster.Double);

    // Test the funcs
    result = Func1(&cluster1);
    result1 = Func2(&cluster);
    printf("\n\nDouble output from DLL function cluster1{Array, DBL}: %lf", result);
    printf("\nDouble output from DLL function cluster{DBL, Array}: %lf", result1);

    return 0;
}

Ниже приведен вывод из Python, который не ожидается. 45.54 должно быть возвращено как вывод обеими функциями.

c:/Users/samkm/Desktop/DLL Demo/test.py
Array from arr_dbl_cluster: 0, 1, 2, 3, 4,
Array from dbl_arr_cluster: 0, 1, 2, 3, 4,
Double from arr_dbl_cluster: 45.54
Double from dbl_arr_cluster: 45.54

Double output from DLL function cluster{Array, DBL}: -2.106485661434095e-37  # int(...) -> 0
Double output from DLL function cluster{DBL, Array}: 45.54

И код C возвращает ожидаемый результат.

Array from cluster1{Array, DBL}: 0, 1, 2, 3, 4,
Array from cluster{DBL, Array}: 0, 1, 2, 3, 4,
Double from cluster1{Array, DBL}: 45.540000
Double from cluster{DBL, Array}: 45.540000

Double output from DLL function cluster1{Array, DBL}: 45.540000
Double output from DLL function cluster{DBL, Array}: 45.540000

LabVIEW code for Func1 Код LabVIEW для func1

LabVIEW code for Func2 Код LabVIEW для func2

Кто-нибудь сталкивался с этой проблемой? Что нужно сделать в этом случае?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...