0

VisualC++を使用しています。

循環バッファを実装しようとしていますが、この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未満の場合、ポインターはバッファーの終わりを正確に指します

なぜこれがこのように起こるのか、そしてそれを修正する方法を誰かが知っているなら、私を助けてください。

前もって感謝します

4

4 に答える 4

2

を削除する必要があると思います* sz。(そして、キャストは必要ないと思います。)

cb->buffer_end = cb->buffer + (capacity-1);

ポインターの算術演算では、指す型のサイズが自動的に考慮されます。

また、 boost::circular_bufferも指摘する必要があります。

于 2011-02-21T12:40:48.967 に答える
2

ポインタ演算を誤解しているようです

cb->buffer_end = (DataFragment *)cb->buffer + (capacity-1)*sz;
cb->head = (DataFragment*)cb->head + cb->sz;
cb->tail = (DataFragment*)cb->tail + cb->sz;

ポインター演算では、基になる型のサイズが既に考慮されています。本当に必要なのは

++cb->head;
++cb->tail;

アイデアがハックすることである場合sizeof(DataFragment)-おそらく構造体のサイズよりも多くのストレージを1つのアイテムに割り当てること-何らかの悪意のある目的のために-最初にポインターをaにキャストする必要がありますchar*(なぜならsizeof(char) == 1)。

cb->tail = (DataFragment*)((char*)cb->tail + cb->sz);

設計上、構造体にはメンバーが多すぎるように見えます:互いに複製し (1 つを指定すると、常に他のメンバーを見つけることができます)、buffer_endメンバーは必要ありません (常に.capacityszsizeof(DataFragment)

また、構造体を割り当てるだけでよいと思います

*(cb->head) = *item;

完全に不必要なキャストがあるようです (おそらくポインター演算の誤解によるものです):

cb->buffer_end = (DataFragment *)cb->buffer + (capacity-1)*sz;

そして、それがC++であると想定されている場合、それには多くの「Cイズム」(型定義されている構造体を使用する、型定義struct XXX var;されているにもかかわらず-を使用するなど)が含まれており、コードは一般に純粋なCスタイルで設計されています(C++の最大の強み、RAIIによる自動リソース管理)。


また、それがあなたに日付clock()を与えることはほとんどないことを指摘してもいいですか:)

于 2011-02-21T12:55:34.273 に答える
1

ポインタの幅は4バイトであると想定しています。これは、すべてのプラットフォーム(x86_64)に当てはまるとは限りません。したがって、memcpy()はsizeof演算子を使用する必要があります。"end = buffer +(capacity --1)* sizeに別のバグがあるようです。cb_push_back()と組み合わせて、1つの要素を割り当てすぎています(またはリングバッファの最後の要素を使用していません)。cb_countが増加します。すべてのpush_backでも、バッファは要素よりも多くの「カウント」を持つことができます。

于 2011-02-21T12:42:22.913 に答える
0

C++ でコーディングする場合は、少なくとも STL を使用してください。std::list を試す

于 2011-02-21T12:44:24.527 に答える