将 Python C 库移植到 "pure" C 的问题
Issue with porting Python C library to "pure" C
我想将一个用 C Python C API 用 C 编写的小型库移植到纯 C library/application。最后我希望它在 C++ 中工作,但我认为在专注于将它放入 C++ 之前让它在没有 python 依赖项的情况下工作更好。
这是我要移植的代码片段:https://github.com/adafruit/Adafruit_DotStar_Pi/blob/master/dotstar.c
这通过 SPI 控制某种类型的 LED。实际上,使用这段代码可以控制数千个 LED。它在 Python 内运行良好,但我将代码移植到 C 应用程序后,一旦超过 256 个 LED 就什么都不做。使用低于 256 个 LED,一切正常。
所以在我看来,这似乎是类型问题或分配问题,出于某种原因,不会导致内存访问冲突。我的测试应用程序没有崩溃,LED 在超过 256 阈值时根本不做任何事情。
我有两段代码,我不能 100% 确定 Python 在做什么,我用我最有根据的猜测代替了。
LED 的所有数据都存储在一个名为 DotStarObject 的结构中,因此我怀疑问题与此结构有关。
首先,我从 DotStarObject 结构中删除了 PyObject_HEAD 宏,据我所知,所有这些所做的只是添加一些 Python 内部需要的东西。
接下来我更改了调用 DotStar_new 函数时分配结构的方式。
首先,我将函数类型从 static PyObject *DotStar_new
更改为 static DotStarObject *DotStar_new
,因为它 returns 指向 DotStarObject 结构的指针。
我认为导致我的错误的罪魁祸首是结构中填充数据的部分。通常 Python 会在这里分配一些内存。据我了解 Pythons tp_alloc
它所做的只是分配所用类型大小的内存(在本例中为 DotStarObject)。
所以这个:
PyTypeObject *type;
DotStarObject *self = NULL;
(...)
// Allocate space for LED data:
if((!n_pixels) || ((pixels = (uint8_t *)malloc(n_pixels * 4)))) {
if((self = (DotStarObject *)type->tp_alloc(type, 0))) {
self->numLEDs = n_pixels;
self->dataMask = 0;
self->clockMask = 0;
self->bitrate = bitrate;
self->fd = -1;
self->pixels = pixels; // NULL if 0 pixels
self->pBuf = NULL; // alloc'd on 1st use
self->dataPin = dPin;
self->clockPin = cPin;
self->brightness = 0;
self->rOffset = rOffset;
self->gOffset = gOffset;
self->bOffset = bOffset;
Py_INCREF(self);
} else if(pixels) {
free(pixels);
}
}
变成了这个(目前,self
分配失败时缺少保护):
DotStarObject *self = (DotStarObject*)malloc(sizeof(DotStarObject));
(...)
if((!n_pixels) || ((pixels = (uint8_t *)malloc(n_pixels * 4)))) {
self->numLEDs = n_pixels;
self->dataMask = 0;
self->clockMask = 0;
self->bitrate = bitrate;
self->fd = -1;
self->pixels = pixels; // NULL if 0 pixels
self->pBuf = NULL; // alloc'd on 1st use
self->dataPin = dPin;
self->clockPin = cPin;
self->brightness = 0;
self->rOffset = rOffset;
self->gOffset = gOffset;
self->bOffset = bOffset;
}
我是不是误解了 (DotStarObject *)type->tp_alloc(type, 0)
在做什么,还是我用 DotStarObject *self = (DotStarObject*)malloc(sizeof(DotStarObject));
正确地替换了它?
如果我遗漏了一些关键信息,可以在这里找到我的完整代码:http://pastebin.com/xddN9JMs
一方面我怀疑这个循环:
for (uint8_t i = 0; i < dotty->numLEDs; ++i){
// setPixelColor(dotty,i,r,g,b);
setPixelColor(dotty,i,r,0,0);
}
您正在为索引使用 8 位类型,无论 dotty->numLEDs
的值如何,它都只允许 256 个值。
我想将一个用 C Python C API 用 C 编写的小型库移植到纯 C library/application。最后我希望它在 C++ 中工作,但我认为在专注于将它放入 C++ 之前让它在没有 python 依赖项的情况下工作更好。
这是我要移植的代码片段:https://github.com/adafruit/Adafruit_DotStar_Pi/blob/master/dotstar.c
这通过 SPI 控制某种类型的 LED。实际上,使用这段代码可以控制数千个 LED。它在 Python 内运行良好,但我将代码移植到 C 应用程序后,一旦超过 256 个 LED 就什么都不做。使用低于 256 个 LED,一切正常。
所以在我看来,这似乎是类型问题或分配问题,出于某种原因,不会导致内存访问冲突。我的测试应用程序没有崩溃,LED 在超过 256 阈值时根本不做任何事情。
我有两段代码,我不能 100% 确定 Python 在做什么,我用我最有根据的猜测代替了。
LED 的所有数据都存储在一个名为 DotStarObject 的结构中,因此我怀疑问题与此结构有关。
首先,我从 DotStarObject 结构中删除了 PyObject_HEAD 宏,据我所知,所有这些所做的只是添加一些 Python 内部需要的东西。
接下来我更改了调用 DotStar_new 函数时分配结构的方式。
首先,我将函数类型从 static PyObject *DotStar_new
更改为 static DotStarObject *DotStar_new
,因为它 returns 指向 DotStarObject 结构的指针。
我认为导致我的错误的罪魁祸首是结构中填充数据的部分。通常 Python 会在这里分配一些内存。据我了解 Pythons tp_alloc
它所做的只是分配所用类型大小的内存(在本例中为 DotStarObject)。
所以这个:
PyTypeObject *type;
DotStarObject *self = NULL;
(...)
// Allocate space for LED data:
if((!n_pixels) || ((pixels = (uint8_t *)malloc(n_pixels * 4)))) {
if((self = (DotStarObject *)type->tp_alloc(type, 0))) {
self->numLEDs = n_pixels;
self->dataMask = 0;
self->clockMask = 0;
self->bitrate = bitrate;
self->fd = -1;
self->pixels = pixels; // NULL if 0 pixels
self->pBuf = NULL; // alloc'd on 1st use
self->dataPin = dPin;
self->clockPin = cPin;
self->brightness = 0;
self->rOffset = rOffset;
self->gOffset = gOffset;
self->bOffset = bOffset;
Py_INCREF(self);
} else if(pixels) {
free(pixels);
}
}
变成了这个(目前,self
分配失败时缺少保护):
DotStarObject *self = (DotStarObject*)malloc(sizeof(DotStarObject));
(...)
if((!n_pixels) || ((pixels = (uint8_t *)malloc(n_pixels * 4)))) {
self->numLEDs = n_pixels;
self->dataMask = 0;
self->clockMask = 0;
self->bitrate = bitrate;
self->fd = -1;
self->pixels = pixels; // NULL if 0 pixels
self->pBuf = NULL; // alloc'd on 1st use
self->dataPin = dPin;
self->clockPin = cPin;
self->brightness = 0;
self->rOffset = rOffset;
self->gOffset = gOffset;
self->bOffset = bOffset;
}
我是不是误解了 (DotStarObject *)type->tp_alloc(type, 0)
在做什么,还是我用 DotStarObject *self = (DotStarObject*)malloc(sizeof(DotStarObject));
正确地替换了它?
如果我遗漏了一些关键信息,可以在这里找到我的完整代码:http://pastebin.com/xddN9JMs
一方面我怀疑这个循环:
for (uint8_t i = 0; i < dotty->numLEDs; ++i){
// setPixelColor(dotty,i,r,g,b);
setPixelColor(dotty,i,r,0,0);
}
您正在为索引使用 8 位类型,无论 dotty->numLEDs
的值如何,它都只允许 256 个值。