2017-07-04 23 views
-2

Ich habe versucht, Warteschlange von Array und Zeigern in C-Sprache zu implementieren. Die Warteschlange durch C Struktur modelliert wirdWarteschlange in C-Array mit Zeigern

// Circular Buffer 
typedef struct{ 
    main_controller_req_t  buffer[BUFFER_SIZE]; // buffer 
    uint16_t     size;     // length of the queue 
    uint16_t     count;     // number of elements present in the queue 
    main_controller_req_t  *p_head;    // pointer to head of the queue (read end) 
    main_controller_req_t  *p_tail;    // pointer to tail of the queue (write end) 
}circular_buffer_t; 

I Funktion für Warteschlangen Initialisierung

void init_cb(circular_buffer_t *p_cb){ 

    p_cb->p_head = p_cb->buffer; 
    p_cb->p_tail = p_cb->buffer; 
    p_cb->count = 0; 
    p_cb->size = BUFFER_SIZE; 

} 

und Funktion zum Einfügen in die Warteschlange

BOOL enqueue_cb(circular_buffer_t *p_cb, main_controller_req_t *p_enq_elem){ 

    if(p_cb->count < p_cb->size){ 

     // queue contains at least one free element 

     taskENTER_CRITICAL(); 

      // insert the element at the tail of queue 
      *(p_cb->p_tail) = *p_enq_elem; 
      // incrementing modulo size 
      p_cb->p_tail = (((p_cb->p_tail++) == (p_cb->buffer + p_cb->size)) ? (p_cb->buffer) : (p_cb->p_tail)); 
      // one element added 
      p_cb->count++; 

     taskEXIT_CRITICAL(); 

     return TRUE; 

    }else{ 

     // queue is full 
     return FALSE; 

    } 

} 

Die enqueue_cb Funktion, bis das funktioniert gut umgesetzt haben Schwanz erreicht BUFFER_SIZE. Dann stürzt das Programm ab und uC wird zurückgesetzt. Das Problem ist in p_tail Zeiger-Update, aber ich verstehe nicht warum . Kann mir bitte jemand helfen? Danke im Voraus.

+1

Ich schlage vor, dass Sie alle Ihre Bibliotheken, die nicht für die CPU auf Ihrem PC (Visual Studio oder ähnlich) abhängig sind. Es erleichtert das Debuggen und erzeugt weniger Fragen. – tilz0R

+1

Bitte geben Sie einen kleinen Teil Ihrer Hauptfunktion an, wo Ihre Nutzung zum Absturz führt. –

+1

@Steve> Sie können p_cb-> p_tail ** und ** in derselben Anweisung nicht mit '++' belegen. (Nun, um fair zu sein, können Sie, machen Sie nur Ihren Code schwierig zu verstehen, auch von sich selbst) – spectras

Antwort

0

Das Problem ist in Ihrem Test ... Sie überprüfen auf Überlauf, aber vor Inkrementierung des Zeigers, dies bewirkt, p_cb->p_tail über das Ende Ihrer Ringpuffer gehen.

p_cb->p_tail = ((p_cb->p_tail++) == (p_cb->buffer + p_cb->size)) 
        ? (p_cb->buffer) 
        : (p_cb->p_tail); 

Sie müssen den Wert des Schwanzes testen nach Inkrementieren.

p_cb->p_tail = (++(p_cb->p_tail) >= (p_cb->buffer + p_cb->size)) 
        ? p_cb->buffer 
        : p_cb->p_tail; 

Nebenbei ist eine verkettete Liste keine sehr effiziente Möglichkeit, einen Ringpuffer zu implementieren. Haben Sie überlegt, eine einfache Fifo-Buffer-Implementierung zu verwenden?

Das Fifo-Konstrukt ist so üblich, dass es nützlich ist, eine universelle Makro-Implementierung für C zu haben. Es ist Thread-sicher (keine Sperren erforderlich), wenn Sie nur einen Hersteller und einen Verbraucher haben.

Diese Makros können vom Compiler sehr einfach optimiert werden.

Es ist ein gutes Werkzeug in der eigenen Toolbox.

// save these macros in a header file. 
#define fifo_reset(fifo) \ 
    { (fifo).head = (fifo).tail = (fifo).buffer; } 

#define fifo_elements(fifo) \ 
    (sizeof((fifo).buffer)/sizeof((fifo).buffer[0]) 

#define fifo_count(fifo) \ 
    (((fifo).tail >= (fifo).head)) ? ((fifo).tail - (fifo).head) : (((fifo).tail - (fifo).head) + fifo_elements(fifo)) 

#define fifo_free_space(fifo) \ 
    (fifo_elements(fifo) - (fifo_count(fifo) + 1)) 

#define __fifo_advance(fifo, ptr) /* this is "private" */\ 
    ((((ptr) + 1) < (fifo).buffer + fifo_elements(fifo))) ? ((ptr) + 1) : (fifo).buffer) 

#define fifo_full(fifo) \ 
    (__fifo_advance(fifo, (fifo).head) == (fifo).tail) 

#define fifo_empty(fifo) \ 
    ((fifo).head == (fifo).tail) 

#define fifo_pop(fifo, el) \ 
    ((fifo).head = ((el) = *(fifo).head, __fifo_advance(fifo, (fifo).head))) 

#define fifo_push(fifo, el) \ 
    ((fifo).tail = (*((fifo).tail) = (el), __fifo_advance(fifo, (fifo).tail))) 

// Now, any struct with head, tail, and fixed-length buffer is a fifo. 
struct char_fifo_128 
{ 
    char buffer[128]; 
    char* head; 
    char* tail; 
}; 

struct main_controller_req_t 
{ 
    // all data types are _movable_ using '=' 
    char any[128]; 
    int data; 
    float more_data; 
    char* dupstr; 
}; 

#define BUFFER_SIZE 256 

struct controller_fifo 
{ 
    main_controller_req_t  buffer[BUFFER_SIZE]; // buffer 
    main_controller_req_t* head; 
    main_controller_req_t* tail; 
}; 

int main() 
{ 
    char c = 0; 
    int elements_stored; 
    controller_fifo queue; 
    main_controller_req_t req; 

    fifo_reset(queue); // MUST call before using fifo 

    // always check if space/data is available. 
    if (!fifo_full(queue)) 
    { 
     fifo_push(queue, req); 
    } 
    elements_stored = fifo_count(queue); 

    if (!fifo_empty(queue)) 
    { 
     fifo_pop(queue, req); 
    } 

    fifo_reset(queue); // fifo reset is NOT thread-safe 


    char_fifo_128* buffer = (char_fifo_128*)malloc(sizeof(char_fifo_128)); 

    fifo_reset(*buffer); 

    if (!fifo_full(*buffer)) 
    { 
     // ... 
     fifo_push(*buffer, req); 
    } 
    elements_stored = fifo_count(*fifo); 

    if (!fifo_empty(*buffer)) 
    { 
     fifo_pop(*buffer, c); 
    } 

    free(buffer); 
    return 0; 
} 
+1

Aber auf jeden Fall, machen Sie bitte die Erhöhung in einer anderen Aussage vor diesem. Es wird den generierten Code nicht ändern, aber es macht es für Nicht-Sprache-Anwälte einfacher zu lesen. Um hier die Aussage korrekt zu lesen, muss man wissen, dass der ternäre Operator garantiert, dass die Nebeneffekte seiner Bedingung sequenziert werden - vor der Berechnung der Werte anderer Operanden. – spectras

+0

Vielen Dank Michael Roy. – Steve

+0

@Steve. Mein Vergnügen, fügte Info als Antwort hinzu. @spectras: Der ++ Operator hat eine wohldefinierte Semantik: '++ i' erhöht 'i' und gibt den inkrementierten Wert zurück. 'i ++' erstellt eine Kopie von 'i', erhöht 'i' und gibt dann den Wert der Kopie zurück, die von 'i' vor dem Inkrement erstellt wurde. Deshalb wird empfohlen, die Form '++ i' zu verwenden, da eine Kopie vermieden wird. –