使用直接指针操作实现Ring缓冲区的问题

时间:2016-10-25 17:55:13

标签: c mingw circular-buffer

我在下面写了环缓冲区的代码。我只想使用没有任何位置指示器的指针。但是在写作的时候我没有得到预期的结果。虽然写入发生,但它在第一次进入后不会停止。它继续下去。读操作似乎是正确的。 我尝试使用调试器进行调试。但令我惊讶的是,if(head>(myRing+AVAILABLE_SIZE*sizeof(myRing[0])))没有在函数writeToRing()函数中执行。调试器正在跳过此步骤。还有第一次head ++没有在这个函数中执行,而代码将首先转到if(head == tail)然后再回到++;无法找到原因。 我正在使用Code :: Blocks with MinGW

#define MAX_SIZE 2
#define AVAILABLE_SIZE (MAX_SIZE-1)

/*
Program to construct and access ring buffer without structure.
This program makes use of pointer. Even without pointer it is possible to manage
*/

int myRing[MAX_SIZE];
int *head=myRing;   // Initialize next element than tail
int *tail=myRing;

enum ERROR_LIST
{
    SUCCESS=0,
    BUFFER_FULL=-1,
    BUFFER_EMPTY=-2
    };

int writeToRing(int data)
{
    head++;
    if(head>(myRing+AVAILABLE_SIZE*sizeof(myRing[0])))
    {
        head=myRing;  //wraps over
    }
    else
    {
        // Do nothing
    }
    if(head==tail)
    {
        head--;
        if(head<myRing)     // In case head is less than starting address. assign max address
        {
            head=(myRing+AVAILABLE_SIZE*sizeof(myRing[0]));
        }
        printf("Buffer full\n");
        return(BUFFER_FULL);
    }
    else
    {
        *head=data;
    }
    return(SUCCESS);
}

 int readFromBuffer(int* data)
 {
     if(tail==head)
     {
         return(BUFFER_EMPTY);
     }
     else
     {
         tail++;
         if(tail>(myRing+AVAILABLE_SIZE*sizeof(myRing[0])))
         {
             tail=myRing;
         }
         *data=*tail;
         return(SUCCESS);
     }
 }

int main()
{
    int option;
    int data;
    while(1)
    {
    printf("Enter Your option. 1 for writing to buffer, 2 for reading from Buffer\n");
    scanf("%d",&option);
    if(option==1)
    {
        printf("Enter the data to be written\n");
        scanf("%d",&data);
        if(writeToRing(data))
        {
            printf("Buffer is Full. Remove the contents first\n");
        }
    }
    else if(option==2)
    {
        if(!readFromBuffer(&data))
        {
            printf("The data read = %d\n",data);
        }
        else
        {
            printf("Buffer is Empty\n");
        }
    }
    else
    {
        printf("Invalid Option\n");
    }

    }
    return(0);
}

编辑: 用另一种方法更新了代码。在此代码中,不会浪费一个数据字节。我测试过并且似乎正在工作。但如果有任何其他问题,请告诉我。对于类型说明符为%u的scanf,有两个警告,需要查看如何修复它。在这种情况下,我基本上想要读取字节。如果我进行整数读取,则没有问题。

#include <stdio.h>
#include <stdint.h>
#define MAX_SIZE 3

uint8_t BUFFER_FULL=0;  // Initially buffer full flag is cleared
uint8_t BUFFER_EMPTY=1;   // Initially buffer empty flag is set

/*
Program to construct and access ring buffer without pointer.
Also this makes use of full buffer and checks for buffer empty or buffer full condition
before calling write or read functionality,
*/

uint8_t myRing[MAX_SIZE];
uint8_t head=0;   // Initialize the head
uint8_t tail=0;   // Initialize the tail
uint8_t maxPosition= MAX_SIZE-1;


void writeToRing(uint8_t data)
{
    head=head+1;
    if(head>maxPosition)
    {
        head=0;
    }
    else
    {
        // Do nothing
    }
    // Write the data to buffer
    myRing[head]=data;
    BUFFER_EMPTY=0;  // Indicate that buffer is not empty

    if(head==tail)
    {
        printf("Buffer full No further data can be written\n");
        BUFFER_FULL=1;
    }
}

void readFromRing(uint8_t* data)
{
    // Initially buffer is empty (BUFFER_EMPTY=1). At that point, calling portion cannot call this function.
    // Later when data is written, writeToRing() function will clear BUFFER_EMPTY flag.

    tail++;
    if(tail>maxPosition)
    {
        tail=0;
    }
    *data=myRing[tail];
    // Once reading is done, ensure that BUFFER_FULL flag is cleared.
    BUFFER_FULL=0;
    if(tail==head)
    {
        printf("Buffer is now Empty. No further reading possible\n");
        BUFFER_EMPTY=1;
    }
}

int main()
{
    uint8_t option;
    uint8_t data;
    while(1)
    {
        printf("Enter Your option. 1 for writing to buffer, 2 for reading from Buffer\n");
        scanf("%u",&option);
        if(option==1)
        {
            if(!BUFFER_FULL)
            {
                printf("Enter the data to be written\n");
                scanf("%u",&data);
                writeToRing(data);
            }
            else
            {
                // Nothing to be done in case buffer is FULL
                printf("Buffer should be cleared first\n");
            }
        }
        else if(option==2)
        {
            if(!BUFFER_EMPTY)
            {
                uint8_t data;
                readFromRing(&data);
                printf("The data read = %d\n",data);
            }
            else
            {
                printf("Buffer is Empty. Write something before you read\n");
            }
        }
        else
        {
            printf("Invalid Option\n");
        }
    }
    return(0);
}

2 个答案:

答案 0 :(得分:2)

正确的形式是:

if(head>(myRing+AVAILABLE_SIZE))
{
...
}

由于myRing是一个指针,&#34; +&#34;运算符本身执行元素大小的乘法运算。

答案 1 :(得分:1)

您可以通过一些改进来简化代码

  1. 添加另一个指针(wrap),指示环形缓冲区的结束。当headtail等于wrap时,是时候将它们设置回缓冲区的开头。

  2. writeToRing函数中,使用临时指针(temp)检查缓冲区是否已满。这样head就不会受到影响,直到您知道写入成功,因此您无需撤消计算。

  3. int myRing[MAX_SIZE];
    int *head = myRing;
    int *tail = myRing;
    int *wrap = &myRing[MAX_SIZE];
    
    int writeToRing( int data )
    {
        int *temp = head+1;
    
        if ( temp == wrap )
            temp = myRing;
    
        if ( temp == tail )
            return BUFFER_FULL;
    
        head = temp;
        *head = data;
        return SUCCESS;
    }
    
    int readFromRing( int *data )
    {
        if ( tail == head )
            return BUFFER_EMPTY;
    
        tail++;
        if ( tail == wrap )
            tail = myRing;
    
        *data = *tail;
        return SUCCESS;
    }
    

    至于为什么调试器很有趣,请确保在调试时关闭优化。调试器很难跟踪优化代码。