2017-02-28 91 views
5

我有以下條目Python字典:轉換Python字典到ctypes的結構

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在一個循環中,使得

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] 

我一直在努力,以獲得正確的語法指定CAarray,至今都失敗了。幫幫我。

另一方面,是否有任何例程/ lib可以處理Python變量和ctypes變量之間的相互轉換?

回答

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命名約定雖然。

+0

對不起rolika,這是行不通的。當ca_array傳遞給C函數myfunc(請參閱查詢)時,我得到所有亂七八糟的值。請注意,myfunc的第一個參數是一個結構CA的數組。 – Rak

3

我創建了一個測試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

太棒了!謝謝馬克,它的工作原理。關鍵部分是用'utf8'編碼字符串。我可以將Rolika的解決方案修改爲C函數正確捕獲的所有值,除了只接收第一個字符的字符串外。你的解決方案幫助解決了最後一點... – Rak