循环缓冲区的结束指针问题
我正在使用 Visual C++。
我正在尝试实现一个循环缓冲区,这个 CB 必须处理特定类型的数据...事实上,它是一个结构数据,其中我们有某种原始数据存储在 char 类型中以及与之关联的日期数据...这是使用结构实现的。
这是更多详细信息的代码:
#include <stdio.h>
#include <time.h>
#include <windows.h>
//data=date_label+raw_data
typedef struct DataFragment
{
char data[4];
clock_t date;
}DataFragment;
typedef struct CircularBuffer
{
DataFragment *buffer; // data buffer
DataFragment *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
DataFragment *head; // pointer to head
DataFragment *tail; // pointer to tail
} CircularBuffer;
void cb_init(struct CircularBuffer *cb, size_t capacity, size_t sz)
{
if((cb->buffer = (DataFragment*) malloc(capacity * sz))!=NULL)
puts("success alocation");
//if(cb->buffer == NULL)
//handle error
cb->buffer_end = (DataFragment *)cb->buffer + (capacity-1)*sz;
cb->capacity = capacity;
cb->count = 0;
cb->sz = sz;
cb->head = cb->buffer;
cb->tail = cb->buffer;
}
void cb_free(struct CircularBuffer *cb)
{
free(cb->buffer);
// clear out other fields too, just to be safe
}
void cb_push_back(struct CircularBuffer *cb, const DataFragment *item)
{
//if(cb->count == cb->capacity)
//handle error when it's full
memcpy(cb->head->data, item->data,4);
cb->head->date=item->date;
cb->head = (DataFragment*)cb->head + cb->sz;
if(cb->head == cb->buffer_end)
cb->head = cb->buffer;
cb->count++;
}
void cb_pop_front(struct CircularBuffer *cb, DataFragment *item)
{
//if(cb->count == 0)
//handle error
memcpy(item->data, cb->tail->data,4);
item->date=cb->tail->date;
cb->tail = (DataFragment*)cb->tail + cb->sz;
if(cb->tail == cb->buffer_end)
cb->tail = cb->buffer;
cb->count--;
}
int main(int argc, char *argv[])
{
struct CircularBuffer pbuf;
pbuf.buffer=NULL;
pbuf.buffer_end=NULL;
pbuf.capacity=0;
pbuf.count=0;
pbuf.head=NULL;
pbuf.sz=0;
pbuf.tail=NULL;
struct CircularBuffer *buf= &pbuf;
size_t sizz = sizeof(DataFragment);
//initialisation of the circlar buffer to a total bytes
//of capacity*sizz=100*sizeof(struct DataFragment)
cb_init(buf,100,sizz);
//temporary container of data
DataFragment temp,temp2;
for(int i=0;i<4;i++)
temp.data[i]='k';
for(int i=0;i<4;i++)
temp2.data[i]='o';
//pushing temporary buffer to the CB...40*2=80<capacity of the CB
for(int i=0;i<40;i++)
{
Sleep(20);
temp.date=clock();
cb_push_back(buf,&temp);
Sleep(10);
temp2.date=clock();
cb_push_back(buf,&temp2);
}
DataFragment temp3;
for(int i=0;i<20;i++)
{
cb_pop_front(buf,&temp3);
printf("%d\n", temp3.data); //print integers....no need of end caracter
}
cb_free(buf);
return 0;
}
当我编译代码时,一切都很好,但是当我调试时,我注意到 buffer_end 指针有问题,它说 bad_pointer....如果容量大于 56,就会发生这种情况.. .我不知道为什么指针不能指向缓冲区的末尾。但是如果容量小于 56,则指针恰好指向缓冲区的末尾
如果有人知道为什么会发生这种情况,以及如何修复它,请帮助我..
提前致谢
I'm using Visual c++.
I'm trying to implement a circular buffer, this CB must handle a specific type of data...in fact, it's a structure data where we have some kind of raw data to be stored in a char type and a date associated to that data...this has been implemented using a strucuture.
here is the code for more details:
#include <stdio.h>
#include <time.h>
#include <windows.h>
//data=date_label+raw_data
typedef struct DataFragment
{
char data[4];
clock_t date;
}DataFragment;
typedef struct CircularBuffer
{
DataFragment *buffer; // data buffer
DataFragment *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
DataFragment *head; // pointer to head
DataFragment *tail; // pointer to tail
} CircularBuffer;
void cb_init(struct CircularBuffer *cb, size_t capacity, size_t sz)
{
if((cb->buffer = (DataFragment*) malloc(capacity * sz))!=NULL)
puts("success alocation");
//if(cb->buffer == NULL)
//handle error
cb->buffer_end = (DataFragment *)cb->buffer + (capacity-1)*sz;
cb->capacity = capacity;
cb->count = 0;
cb->sz = sz;
cb->head = cb->buffer;
cb->tail = cb->buffer;
}
void cb_free(struct CircularBuffer *cb)
{
free(cb->buffer);
// clear out other fields too, just to be safe
}
void cb_push_back(struct CircularBuffer *cb, const DataFragment *item)
{
//if(cb->count == cb->capacity)
//handle error when it's full
memcpy(cb->head->data, item->data,4);
cb->head->date=item->date;
cb->head = (DataFragment*)cb->head + cb->sz;
if(cb->head == cb->buffer_end)
cb->head = cb->buffer;
cb->count++;
}
void cb_pop_front(struct CircularBuffer *cb, DataFragment *item)
{
//if(cb->count == 0)
//handle error
memcpy(item->data, cb->tail->data,4);
item->date=cb->tail->date;
cb->tail = (DataFragment*)cb->tail + cb->sz;
if(cb->tail == cb->buffer_end)
cb->tail = cb->buffer;
cb->count--;
}
int main(int argc, char *argv[])
{
struct CircularBuffer pbuf;
pbuf.buffer=NULL;
pbuf.buffer_end=NULL;
pbuf.capacity=0;
pbuf.count=0;
pbuf.head=NULL;
pbuf.sz=0;
pbuf.tail=NULL;
struct CircularBuffer *buf= &pbuf;
size_t sizz = sizeof(DataFragment);
//initialisation of the circlar buffer to a total bytes
//of capacity*sizz=100*sizeof(struct DataFragment)
cb_init(buf,100,sizz);
//temporary container of data
DataFragment temp,temp2;
for(int i=0;i<4;i++)
temp.data[i]='k';
for(int i=0;i<4;i++)
temp2.data[i]='o';
//pushing temporary buffer to the CB...40*2=80<capacity of the CB
for(int i=0;i<40;i++)
{
Sleep(20);
temp.date=clock();
cb_push_back(buf,&temp);
Sleep(10);
temp2.date=clock();
cb_push_back(buf,&temp2);
}
DataFragment temp3;
for(int i=0;i<20;i++)
{
cb_pop_front(buf,&temp3);
printf("%d\n", temp3.data); //print integers....no need of end caracter
}
cb_free(buf);
return 0;
}
When I compile the code, everything is fine, but when I debug, I noticed a problem with the buffer_end pointer, it says bad_pointer....this happens if the capacity is greater than 56...I don't know why the pointer can't point to end of the buffer.But if the capacity is less than 56 the pointer points exactly on the end of the buffer
If anyone knows why this happens like this, and how to fix it, please help me..
thanks in advance
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您似乎误解了指针算术
指针算术已经考虑了基础类型的大小。您真正需要的是
如果想法是破解
sizeof(DataFragment)
- 也许为一项分配比结构大小更多的存储空间 - 出于某种邪恶的目的 - 您需要首先转换指向char*
的指针(因为sizeof(char) == 1
)。从设计角度来看,该结构似乎有太多成员:
buffer_end
和capacity
彼此重复(给定一个,您总是可以找到另一个),并且sz< /code> 成员不是必需的(它应该始终是
sizeof(DataFragment)
。另外,我相信你可以只分配结构
,似乎完全不必要的强制转换(可能是由于对指针算术的误解造成的) :
如果它应该是 C++,那么它包含很多“C-isms”(typedeffing 结构,使用
struct XXX var;
- 尽管已经对其进行了 typedeffed 等),并且代码通常是以纯 C 风格设计(没有利用 C++ 的最大优势,即使用 RAII 进行自动资源管理)。我还可以指出,
clock()
很难为您提供日期。 :)It seems you are misunderstanding pointer arithmetic
Pointer arithmetic already takes into account the size of the underlying type. All you really need is
If the idea is to hack around
sizeof(DataFragment)
- perhaps to allocate more storage for one item than the struct's size - for some evil purpose - you'll need to first cast the pointer to achar*
(becausesizeof(char) == 1
).Design-wise the struct appears to have too many members:
buffer_end
andcapacity
duplicate each other (given one you can always find the other), and thesz
member is not necessary (it should always besizeof(DataFragment)
.Also, I believe you can just assign structs
there seem to be completely unnecessary casts (probably resulting from the misunderstanding of pointer arithmetic):
And if it is supposed to be C++, then it contains lots of "C-isms" (typedeffing structs, using
struct XXX var;
- despite having it typedeffed, etc), and the code is generally designed in a purely C style (not taking advantage of C++'s greatest strength, automatic resource management with RAII).May I also point out that
clock()
hardly gives you a date :)我认为您需要删除
* sz
。 (而且我认为您不需要强制转换。)指针的算术会自动考虑所指向类型的大小。
我还应该指出 boost::circular_buffer 。
I think you need to remove the
* sz
. (And I don't think you need the cast.)Arithmetic on pointers automatically accounts for the size of the type pointed to.
I should also point out boost::circular_buffer.
你假设指针是 4 字节宽。并非所有平台 (x86_64) 上都是如此。因此,memcpy() 应该使用 sizeof 运算符。
似乎还有另一个错误“end = buffer + (capacity - 1) * size”。与 cb_push_back() 结合使用,您分配的一个元素过多(或者您没有使用环形缓冲区的最后一个元素)。cb_count 增加在每个push_back中也是如此,所以你的缓冲区可以有比元素更多的“计数”。
you are assuming that pointers are 4 byte wide. This may not be the case on all platforms (x86_64). Hence, the memcpy()'s should make use of the sizeof operator.
There seems to be another bug with "end = buffer + (capacity - 1 ) * size. In conjunction with cb_push_back() you are allocating one element too much (or you are not using the last element of the ringbuffer). cb_count gets increased in every push_back too, so your buffer can have more "counts" than elements.
如果你打算用 C++ 编写代码,至少使用 STL。尝试 std::list
If you are going to code in C++, at least use STL. Try std::list