将Python字典转换为ctypes结构

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

我有一个包含以下条目的 Python 字典:

Tmp={'Name1': [10.0, 20.0, 'Title1', 1], 'Name2': [5.0, 25.0, 'Title2', 2]}

我想将其传递给 C 函数,其中函数定义为:

struct CA {
   char *Keys;
   float *Values;
   char *Title;
   int Index;
};

void myfunc (struct CA *in, int n);

在 Python 方面,我创建了一个等效的 ctypes 结构:

class CA(ctypes.Structure):
   _fields_ = [("Keys", ctypes.POINTER(ctypes.c_char_p)), 
               ("Values", ctypes.POINTER(ctypes.c_float)), 
               ("Title", ctypes.POINTER(ctypes.c_char_p)), 
               ("Index", ctypes.c_int)]

并使用以下方法创建了一个 CA 数组:

CAarray = CA * 2

现在我想在循环中将 Tmp 分配给 CAarray,这样

k = Tmp.keys()
for (j, _) in enumerate(k):
   CAarray[j].Keys   = _ 
   CAarray[j].Values = Tmp[_][:2] 
   CAarray[j].Title  = Tmp[_][2]
   CAarray[j].Index  = Tmp[_][3]

我一直在努力使语法正确,但到目前为止都失败了。帮助。

另外,是否有任何例程/lib可以处理Python变量和ctypes变量之间的相互转换?

python c dictionary ctypes
2个回答
10
投票

我创建了一个测试 DLL 来验证该结构是否能够正确通过。

#include <stdio.h>

struct CA {
   char* Keys;
   float* Values;
   char* Title;
   int Index;
};

__declspec(dllexport) void myfunc (struct CA* in, int n)
{
    int i;
    for(i = 0; i < n; ++i)
    {
        printf("%d: Keys = %s\n", i, in[i].Keys);
        printf("%d: Values = %f %f\n", i, in[i].Values[0], in[i].Values[1]);
        printf("%d: Title = %s\n", i, in[i].Title);
        printf("%d: Index = %d\n", i, in[i].Index);
    }
}

我是这样称呼它的:

#!python3
from ctypes import *

class CA(Structure):
    _fields_ = [('Keys', c_char_p),
                ('Values', POINTER(c_float)),
                ('Title', c_char_p),
                ('Index', c_int)]

Tmp={'Name1': [10.0, 20.0, 'Title1', 1], 'Name2': [5.0, 25.0, 'Title2', 2]}

# repackage Tmp as a list of CA structures
ca_list = []
for k, v in Tmp.items():
    ca = CA()
    ca.Keys = k.encode('utf8') # Python 3 strings are Unicode, char* needs a byte string
    ca.Values = (c_float * 2)(v[0], v[1]) # Interface unclear, how would target function know how many floats?
    ca.Title = v[2].encode('utf8')
    ca.Index = v[3]
    ca_list.append(ca)

# repackage python list of CAs to ctype array of CAs
ca_array = (CA * len(ca_list))(*ca_list)

dll = CDLL('./test')
dll.myfunc.argtypes = POINTER(CA), c_int
dll.myfunc.restype = None

dll.myfunc(ca_array, len(ca_array))

输出:

0: Keys = Name1
0: Values = 10.000000 20.000000
0: Title = Title1
0: Index = 1
1: Keys = Name2
1: Values = 5.000000 25.000000
1: Title = Title2
1: Index = 2

0
投票

对此不太确定,但它似乎有效:

tmp = {'Name1': [10.0, 20.0, 'Title1', 1], 'Name2': [5.0, 25.0, 'Title2', 2]}

class CA(ctypes.Structure):
    _fields_ = [("key", ctypes.POINTER(ctypes.c_wchar_p)),
           ("values", ctypes.POINTER(ctypes.c_float)),
           ("title", ctypes.POINTER(ctypes.c_wchar_p)),
           ("index", ctypes.c_int)]

CAArray = CA * 2
ca_array = CAArray()

for ca, key in zip(ca_array, tmp):
    ca.key = ctypes.pointer(ctypes.c_wchar_p(key))
    ca.values = ctypes.pointer(ctypes.c_float(tmp[key][0]))
    ca.title = ctypes.pointer(ctypes.c_wchar_p(tmp[key][2]))
    ca.index = tmp[key][3]

for ca in ca_array:
    print(ca.key[0], ca.values[0], ca.values[1], ca.title[0], ca.index)

不过我坚持使用 Python 命名约定。

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