使用直接指针操作的环形缓冲区实现问题
Issues with Ring buffer implementation using direct pointer manipulation
我已经为环形缓冲区编写了以下代码。我只想使用没有任何位置指示器的指针。但是我在写作时没有得到预期的结果。尽管发生写入,但它不会在第一次进入后停止。它继续进一步。读取操作似乎是正确的。
我尝试使用调试器进行调试。但令我惊讶的是,if(head>(myRing+AVAILABLE_SIZE*sizeof(myRing[0])))
没有在函数 writeToRing() 函数中执行。调试器正在跳过此步骤。同样第一次 head++ 没有在这个函数中执行,而是代码将首先转到 if(head==tail) 然后返回到 head++;找不到原因。
我正在使用 Code::Blocks 和 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);
}
正确的形式是:
if(head>(myRing+AVAILABLE_SIZE))
{
...
}
由于 myRing 是指针,“+”运算符本身执行元素大小的乘法运算。
您可以进行一些改进来简化代码
添加另一个指针 (wrap
) 来标记环形缓冲区的结尾。当 head
和 tail
等于 wrap
时,就该将它们设置回缓冲区的开头。
在writeToRing
函数中,使用临时指针(temp
)检查缓冲区是否已满。这样 head
不受影响,直到您知道写入将成功,因此您不需要撤消计算。
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;
}
至于为什么调试器表现得很滑稽,请确保在调试时关闭优化。调试人员很难遵循优化代码。
我已经为环形缓冲区编写了以下代码。我只想使用没有任何位置指示器的指针。但是我在写作时没有得到预期的结果。尽管发生写入,但它不会在第一次进入后停止。它继续进一步。读取操作似乎是正确的。
我尝试使用调试器进行调试。但令我惊讶的是,if(head>(myRing+AVAILABLE_SIZE*sizeof(myRing[0])))
没有在函数 writeToRing() 函数中执行。调试器正在跳过此步骤。同样第一次 head++ 没有在这个函数中执行,而是代码将首先转到 if(head==tail) 然后返回到 head++;找不到原因。
我正在使用 Code::Blocks 和 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);
}
正确的形式是:
if(head>(myRing+AVAILABLE_SIZE))
{
...
}
由于 myRing 是指针,“+”运算符本身执行元素大小的乘法运算。
您可以进行一些改进来简化代码
添加另一个指针 (
wrap
) 来标记环形缓冲区的结尾。当head
和tail
等于wrap
时,就该将它们设置回缓冲区的开头。在
writeToRing
函数中,使用临时指针(temp
)检查缓冲区是否已满。这样head
不受影响,直到您知道写入将成功,因此您不需要撤消计算。
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;
}
至于为什么调试器表现得很滑稽,请确保在调试时关闭优化。调试人员很难遵循优化代码。