Ich lerne verschiedene Möglichkeiten, wie Code in C
zu Python
geschrieben werden, weil ich eine API für ein Mikrochip-Gerät, die ziemlich ... mühsam zu arbeiten, und ich würde gerne mein Leben in der Zukunft leichter machen, indem ich einen Python
Wrapper dafür hinzufüge, der mir erlauben wird, Sachen viel schneller zu prüfen. Eine Möglichkeit, das zu tun, ist die Verwendung des Moduls, das seinen Benutzer sogar mit verify()
versorgt, das im Grunde den C
Compiler anruft, um zu überprüfen, ob das bereitgestellte cdef(...)
korrekt ist.Python CFFI - nicht formatierte Python-String als Byte-Array in Funktionsaufruf verwenden
Ich habe ein kleines Projekt geschrieben, so dass ich zuerst lernen kann, wie man richtig verwendet . Es besteht aus zwei Teilen
Bibliothek - geschrieben in C. Ich benutze
cmake
undmake
entsprechend seinen Code zu kompilieren:CMakeLists.txt
project(testlib_for_cffi) cmake_minimum_required(VERSION 2.8) set(CMAKE_BUILD_TYPE Release) set(CMAKE_CXX_FLAGS "-fPIC ${CMAKE_C_FLAGS}") # Debug build set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -g -O0") # Release build set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os") aux_source_directory(. SRC_LIST) add_library(testcffi SHARED ${SRC_LIST}) # Not required for the library but needed if I want to check for memory leaks with Valgrind set(SRC main.c) add_executable(${PROJECT_NAME} ${SRC}) target_link_libraries(${PROJECT_NAME} PUBLIC testcffi)
testcffi.h
typedef struct { double x; double y; double z; char *label; } point_t; // Creation, printing and deletion point_t* createPoint(double x, double y, double z, char *label); void printPoint(point_t *point); void deletePoint(point_t *point);
testcffi.c
#include "testcffi.h" #include <stdio.h> #include <malloc.h> point_t* createPoint(double x, double y, double z, char *label) { point_t *p = malloc(sizeof(point_t)); p->x = x; p->y = y; p->z = z; p->label = label; return p; } void printPoint(point_t *point) { if(point == NULL) return; printf("Data:\n\tx : %f\n\ty : %f\n\tz : %f\n\tmsg : \"%s\"\n", point->x, point->y, point->z, point->label); } void deletePoint(point_t *point) { if(point == NULL) return; free(point); point = NULL; }
Prüfregeln in Python - der Code zeigt die Verwendung der
struct
zusammen mit den drei Funktionen aus der Bibliothek oben:#!/usr/bin/python3 from cffi import FFI import random ffi = FFI() # Add library's header ffi.cdef(''' typedef struct { double x; double y; double z; char * label; } point_t; // Creation, printing and deletion point_t * createPoint(double x=0., double y=0., double z=0., char *label="my_label"); void printPoint(point_t *point); void deletePoint(point_t *point); ''') # Load shared object from subdirectory `build` CLibTC = ffi.dlopen('build/libtestcffi.so') def createList(length=5): if len: lst = [] for i in range(0, length): lst.append(CLibTC.createPoint( float(random.random()*(i+1)*10), float(random.random()*(i+1)*10), float(random.random()*(i+1)*10), b'hello' # FIXME Why does ONLY this work? # ('point_%d' % i).encode('utf-8') # NOT WORKING # 'point_{0}'.format(str(i)).encode('utf-8') # NOT WORKING # ffi.new('char[]', 'point_{0}'.format(str(i)).encode('utf-8')) # NOT WORKING )) return lst return None def printList(lst): if lst and len(lst): for l in lst: CLibTC.printPoint(l) list_of_dstruct_ptr = createList(10) printList(list_of_dstruct_ptr)
Das Problem com es aus dem Byte-Array, das ich meinen Python
String umwandeln muss, um die Daten an die entsprechende Stelle in meinem C
Code zu übergeben.
Der obige Code funktioniert, aber ich möchte andere als ähnliche Zeichenfolgen wie b'hello'
verwenden. Deshalb habe ich versucht, die format()
(zusammen mit ihrer Kurzform %
) in Python
zu kombinieren, eine Reihe von Buchstaben und eine Zahl aber. Es hat nicht geklappt. Ich bekomme entweder ""
als Wert für die label
Parameter meiner point_t
struct
oder ich bekomme eine seltsame wechselnde Müll-Daten (meist seltsame Zeichen, die weder Buchstaben noch Ziffern sind).
Ich dachte, dass ich die encode()
Funktion falsch benutze, aber wenn ich es innerhalb meiner interaktiven Shell Python
getestet habe, bekam ich die gleiche Ausgabe wie mit b'...'
.
Irgendeine Idee, was hier vor sich geht?
A nice-to-know Frage: Von dem, was ich bisher gelesen habe scheint es, dass cffi
die Garbage-Collection in Python
verwendet die dynamisch zugewiesenen Speicher in Ihrem C-Code freigegeben.Ich habe es mit einer Reihe von Punkten getestet, aber ich möchte sicherstellen, dass dies tatsächlich immer der Fall ist.
Update: Okay, so scheint es, dass sich die Dinge ohne new(...)
in diesem Fall jedoch funktionieren alle Werte die gleiche wie die letzte in der Schleife sind. Zum Beispiel, wenn die Schleife bis 10 geht, dann haben alle struct
Python-Objekte die 10 in ihren Etiketten. Dies scheint ein Bezugsproblem zu sein. Wenn ich new(...)
verwende, bekomme ich Mülldaten.
: O Absolut richtig und ich habe es total vermisst, obwohl ich es 1000 mal in der Dokumentation gelesen habe. LOL Wenn man also einen Wrapper einer C-basierten API erstellt, muss man spezielle Objekte erstellen, die eine bessere Verwaltung solcher Referenzen ermöglichen. Ich danke dir sehr. Ich habe einige weiße Haare bekommen, die während meines Kampfes wachsen, um das zu lösen. – rbaleksandar