Hallo an alle. Ich habe mich entschlossen, den C / C ++ - Artikel von Python leicht zu ergänzen.
Das Übergeben von Standardtypen wie int, bool, float usw. ist ziemlich einfach, aber nicht sehr notwendig. Python selbst wird mit solchen Daten schnell fertig werden, und es ist unwahrscheinlich, dass jemand einen Teil dieses Codes in die C / C ++ - Bibliothek übertragen muss.
Aber die Übertragung von großen Datenarrays oder noch besser zweidimensionalen Datenarrays oder sogar zweidimensionalen Arrays von Objekten.
Alles hier ist nicht so offensichtlich, und es gibt eine Reihe von Dingen, die meiner Meinung nach für diejenigen hervorgehoben werden können, die Codeabschnitte, die für den Python-Interpreter schwierig sind, erheblich beschleunigen möchten.
Das Beispiel unter dem Schnitt ist für die Verwendung nicht sehr nützlich, aber ich denke, es reicht aus, um alle Nuancen dieses Verfahrens hervorzuheben.
Geben Sie sofort den Quellcode der Bibliotheksdateien an.
py_list2c_array.h
#ifndef _PY_LIST_2_C_ARRAY_H_ #define _PY_LIST_2_C_ARRAY_H_ #include <stdio.h> typedef struct { int value; wchar_t* name; } Item; extern "C" __declspec(dllexport) int sum_diagonal(Item** field, size_t size); #endif
py_list2c_array.cpp
Auch hier ist alles Standard, außer dass ich die Verwendung der Funktion wprintf () zum Drucken von Zeilen wie wchar_t * beachte.
py_list2c_array.py
Und jetzt das Wichtigste. Ich werde den Quellcode eines Python-Skripts mit einer Beschreibung wichtiger Punkte geben.
import ctypes class PyItem: def __init__(self, value, name): self.value = value self.name = name class CItem(ctypes.Structure): _fields_ = [ ('value', ctypes.c_int), ('name', ctypes.c_wchar_p) ] def create_list(size): return [[PyItem(int(str(i+1)+str(j+1)), 'item{}{}'.format(i+1, j+1)) for j in range(size)] for i in range(size)] def py_list2c_array(py_list, size): rowType = CItem * size resultType = ctypes.POINTER(CItem) * size result = resultType() for i in range(size): row = rowType() for j in range(size): row[j] = CItem() row[j].value = py_list[i][j].value row[j].name = ctypes.c_wchar_p(py_list[i][j].name) result[i] = ctypes.cast(row, ctypes.POINTER(CItem)) return ctypes.cast(result, ctypes.POINTER(ctypes.POINTER(CItem))) if __name__ == '__main__': sLib = ctypes.cdll.LoadLibrary('./py_list2c_array.dll') size = 4 py_list = create_list(size) c_array = py_list2c_array(py_list, size) sLib.sum_diagonal.argtypes = [ctypes.POINTER(ctypes.POINTER(CItem)), ctypes.c_size_t] sLib.sum_diagonal.restype = ctypes.c_int result = sLib.sum_diagonal(c_array, ctypes.c_size_t(size)) print(': {}'.format(result))
Details
Betrachten wir einige Funktionen zum Erstellen von ctypes-Arrays. Zu diesem Zweck werden wir uns die Funktion zum Konvertieren einer Liste in das Array py_list2c_array genauer ansehen. Sie müssen zuerst die Typen angeben.
Der Typ jeder Zeile im Array ist definiert als der Elementtyp multipliziert mit der Anzahl der Elemente.
rowType = CItem * size
Ein Array-Typ ist definiert als der Zeilentyp des Arrays multipliziert mit der Anzahl der Zeilen.
Im Folgenden werde ich etwas über ctypes.POINTER (). ResultType = ctypes.POINTER (CItem) * size erläutern
Erstellen Sie als Nächstes das resultierende Array .result = resultType ()
Und in der Schleife erstellen wir jede Zeile als eindimensionales Array .row = rowType ()
Erstellen Sie als Nächstes in einer verschachtelten Schleife jedes Element des Arrays und weisen Sie der Struktur Werte aus der Liste der Objekte zu. Python.row [j] = CItem ()
row [j] .value = py_list [i] [j] .value
Zeile [j] .name = ctypes.c_wchar_p (py_list [i] [j] .name)
Dann sollte jede erstellte Zeile mit Elementen in einen Zeigertyp auf ein Array von Objekten konvertiert und der Zelle des resultierenden Arrays zugewiesen werden.
Ich werde unten über die Funktion ctypes.cast () schreiben .result [i] = ctypes.cast (row, ctypes.POINTER (CItem))
Konvertieren Sie natürlich das gesamte Array in einen Zeiger. Geben Sie ctypes.cast zurück (Ergebnis, ctypes.POINTER (ctypes.POINTER (CItem)).
ctypes.POINTER
Ctypes hat ctypes.POINTER () - gibt an, dass ein Zeiger verwendet wird. Beispiel: ctypes.POINTER (CItem) gibt an, dass es sich um einen Zeiger auf eine CItem () -Struktur handelt.
Dementsprechend können wir mit der Zeile: ctypes.POINTER (ctypes.POINTER (CItem)) angeben, dass es sich um einen Zeiger auf einen Zeiger auf eine CItem-Struktur handelt, oder in C ++ CItem ** A gibt es ctypes.pointer () . Diese Funktion gibt einen Zeiger auf ein Objekt zurück. Zum Beispiel: item = CItem ()
pointer = ctypes.pointer (item)
Sie sollten nicht verwechselt werden, da ihre Bedeutung völlig anders ist.
ctypes.cast ()
Betrachten Sie nun die sehr wichtige Funktion ctypes.cast (). Diese Funktion ähnelt statisch_cast () aus C ++.
Es ermöglicht Ihnen, sehr wichtige Casts zu machen.
Beim Erstellen eines Array-Typs beispielsweise: rowType = CItem * 4
row = rowType ()
In diesem Fall ist row ein Speicherbereich von 4 Elementen von CItem-Strukturen.
In dieser Form können wir diese Daten natürlich nicht verwenden. Aber wenn wir die Cast-Funktion für sie verwenden: array_pointer = ctypes.cast (row, ctypes.POINTER (CItem))
In diesem Fall ist array_pointer bereits ein Zeiger auf einen Speicherbereich mit 4 CItem-Strukturen.
Der erste Parameter ist der erstellte Speicherbereich mit Array-Elementen, und der zweite Parameter ist der Typ, in den die angegebene Region konvertiert werden soll. Nun, er scheint die Hauptpunkte beim Übertragen von Datenarrays mit ctypes hervorzuheben.
Ich hoffe, dieser Artikel wird Ihnen helfen, schneller und vollständiger mit der wunderbaren ctypes-Bibliothek umzugehen.