かなり面倒な Microchip デバイス用の API を持っているので、コードC
をインクルードするさまざまな方法を学んでいます。これにより、テストをはるかに高速に行うことができます。それを行う1つの方法は、基本的にコンパイラーを呼び出して、提供されたものが正しいかどうかをチェックすることをユーザーに提供するモジュールを使用することです。Python
Python
cffi
verify()
C
cdef(...)
最初に適切に使用する方法を学ぶことができるように、小さなプロジェクトを作成しましたcffi
。2つの部分で構成されています
ライブラリ- C で書かれています。私はそれに応じてそのコードをコンパイルするために使用
cmake
しmake
ます。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; }
Python でのテスト コード
struct
- コードは、上記のライブラリの 3 つの関数と共にの使用法を示しています。#!/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)
Python
問題は、コード内のそれぞれの場所にデータを渡すために文字列を変換する必要があるバイト配列に起因しC
ます。
上記のコードは機能していますが、 に似た他の文字列を使用したいと思いますb'hello'
。そのため、format()
(短い形式の とともに%
) inを使用Python
して、一連の文字と数字を組み合わせようとしましたが、. うまくいきませんでした。my のパラメーターの""
値として取得するか、奇妙な交互のガベージ データ (文字でも数字でもないほとんどの奇妙な文字) を取得します。label
point_t
struct
encode()
関数を間違って使用していると思いましたが、Python
インタラクティブシェル内でテストしたところ、 を使用した場合と同じ出力が得られましたb'...'
。
ここで何が起こっているのか分かりますか?
知っておくと便利な質問:これまで読んだことからcffi
、ガベージ コレクションを使用してPython
、C コードで動的に割り当てられたメモリの割り当てを解除しているようです。たくさんのポイントでテストしましたが、これが実際に常に当てはまることを確認したいと思います。
更新:
わかりました。new(...)
動作しないように見えますが、その場合、すべての値はループ内の最後の値と同じです。たとえば、ループが 10 に達すると、すべてのstruct
Python オブジェクトのラベルに 10 が含まれます。これは参照の問題のようです。使用するnew(...)
と、ガベージデータが取得されます。