- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在学习如何将用 C
编写的代码包含到 Python
中,因为我有一个用于 Microchip 设备的 API,这对于我希望通过为其添加一个 Python 包装器来让我将来的生活更轻松,这将使我能够更快地测试东西。一种方法是使用 cffi 模块,该模块甚至为用户提供了 verify() ,该模块基本上调用 C 编译器来检查是否提供的 cdef(...)
是正确的。
我编写了一个小项目,以便我可以首先学习如何正确使用cffi
。它由两部分组成
Library - 用 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
以及上述库中的三个函数的用法:
#!/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'
的其他字符串。这就是为什么我尝试在 Python
中使用 format()
(及其简写形式 %
)来组合一堆字母和一个数字但是。但没有成功。我要么将 ""
作为我的 point_t
struct
的 label
参数的值,要么得到一个奇怪的交替垃圾数据(主要是既不是字母也不是数字的奇怪字符)。
我认为我错误地使用了 encode()
函数,但是当我在 Python
交互式 shell 中测试它时,我得到了与使用 相同的输出b'...'
.
知道这是怎么回事吗?
<小时/>一个很高兴知道的问题:从我到目前为止所读到的内容来看,cffi
似乎使用了Python
中的垃圾收集> 释放 C 代码中动态分配的内存。我已经用很多点对其进行了测试,但我想确保实际上总是如此。
更新:好吧,看起来没有 new(...)
的东西确实可以工作,但是在这种情况下,所有值都与循环中的最后一个值相同。例如,如果循环达到 10,则所有 struct Python 对象的标签中都将包含 10。这似乎是一个引用问题。当我使用 new(...)
时,我得到垃圾数据。
最佳答案
在您的 C 代码中,point_t
结构在 label
中保存一个 char *
,即指向内存中其他位置的指针。如果您创建 10 个 point_t 结构,它们将保存指向内存中其他位置的 10 个字符串的指针。只要您使用 point_t
结构,您就必须确保这 10 个字符串保持事件状态。 CFFI无法猜测有这样的关系。当您执行调用 CLibTC.createPoint(..., some_string)
时,CFFI 会在调用周围分配一个 char[]
数组并复制 some_string
在其中,但是这个 char[]
内存在调用后被释放。
改用这种代码:
c_string = ffi.new("char[]", some_string)
lst.append(createPoint(..., c_string))
keepalive.append(c_string)
其中 keepalive
是另一个列表,只要您需要 point_t
包含有效的标签
,您就必须确保该列表保持事件状态' s。
关于Python CFFI - 无法在函数调用中使用格式化的 Python 字符串作为字节数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38282126/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!