反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。
循环buffer即循环缓冲区,顾名思义,就是可以不断写不断读的一个局域,在缓冲区写满之后,如果还没有读取就不能继续写了,否则会把原来的覆盖掉。
所以说这是个循环读写的过程,写指针写一个字节移动一次,读指针读一个字节移动一次,移动到buff的末尾位置,又从开始位置进行读写。
重点代码分析:
1、计算空闲空间/数据空间大小:
设定总空间为size-1,始终保留1个字节,如果剩余一个字节空间,就表示buff已满。
先看看负数的二进制我们来求-1的二进制:
1、先取1的原码:00000000 00000000 00000000 00000001
2、得反码: 11111111 11111111 11111111 11111110
3、得补码: 11111111 11111111 11111111 11111111
可见,-1在计算机里用二进制表达就是全1。16进制为:0xFFFFFF
所以这里如果涉及到负数运算就需要注意了!
int rb_data_size (Ringbuff *rb) //计算数据空间大小
{
return ( (rb->wr_pointer - rb->rd_pointer) & (rb->size -1));
}
int rb_free_size (Ringbuff *rb) //计算空闲空间大小
{
return ( rb->size - 1 - rb_data_size(rb));
}
这里读写都是对于8的整数倍buf来操作的,所以定义的buf空间必须是8的整数倍。
2、写操作
数据写如是靠写指针来指定从哪里开始写,所以写指针的位置有决定性作用。
流程:
- 判断写入的数据len是否大于循环buff空间
- 如果超出,自动截断写入的数据
- 写指针加上len之后是否超过buff末尾,超过之后需要把多余的循环写入前面的空闲buff中
- 最后重新设置写指针位置
int rb_write (Ringbuff *rb, u_char *buf, int len)
{
int rb_freesize = rb_free_size(rb); //空闲空间大小
int pos = 0; //读指针位置
if (len > rb_freesize)
{
len = rb_freesize; //输入超过空闲空间,自动截断
}
else
{
rb_freesize = len;
}
pos = rb->wr_pointer;
if (pos + len > rb->size) //如果写入的数据加上超过循环buff大小
{
memcpy(rb->buff + pos, buf, rb->size - pos); //先拷贝未超过那部分,剩下的写入前面那部分空闲空间
buf += rb->size-pos; //移动buf
len -= rb->size-pos; //剩余那部分长度
pos = 0; //将读指针重新放在最开始位置
}
memcpy(rb->buff + pos,buf,len);
rb->wr_pointer = pos + len; //设置写指针位置
return rb_freesize;
}
写过程和读过程是个相反的过程,思想是一样的。
完整代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct ring_buff
{
u_char *buff; //定义buff空间,用于存储数据
int wr_pointer; //写指针
int rd_pointer; //读指针
int size;
};
typedef struct ring_buff Ringbuff;
int rb_data_size (Ringbuff *rb) //计算数据空间大小
{
return ( (rb->wr_pointer - rb->rd_pointer) & (rb->size -1));
}
int rb_free_size (Ringbuff *rb) //计算空闲空间大小
{
return ( rb->size - 1 - rb_data_size(rb));
}
void rb_init (Ringbuff *rb,u_char *buf,int size)
{
memset(rb,0,sizeof(Ringbuff));
rb->rd_pointer = 0;
rb->wr_pointer = 0;
rb->buff = buf;
rb->size = size;
}
void clear (Ringbuff *rb)
{
memset(rb->buff,0,rb->size);
rb->rd_pointer = 0;
rb->wr_pointer = 0;
}
int rb_write (Ringbuff *rb, u_char *buf, int len)
{
int rb_freesize = rb_free_size(rb); //空闲空间大小
int pos = 0; //读指针位置
if (len > rb_freesize)
{
len = rb_freesize; //输入超过空闲空间,自动截断
}
else
{
rb_freesize = len;
}
pos = rb->wr_pointer;
if (pos + len > rb->size) //如果写入的数据加上超过循环buff大小
{
memcpy(rb->buff + pos, buf, rb->size - pos); //先拷贝未超过那部分,剩下的写入前面那部分空闲空间
buf += rb->size-pos;
len -= rb->size-pos;
pos = 0;
}
memcpy(rb->buff + pos,buf,len);
rb->wr_pointer = pos + len; //设置写指针位置
return rb_freesize;
}
int rb_read (Ringbuff *rb, u_char * buf, int max)
{
int datasize=rb_data_size(rb);
int pos = 0;
if (max > datasize)
{
max = datasize;
}
else
{
datasize = max;
}
pos = rb->rd_pointer;
if (pos + max > rb->size)
{
memcpy(buf,rb->buff + pos,rb->size - pos);
buf +=rb->size;
max -=rb->size;
pos = 0;
}
memcpy(buf,rb->buff + pos,max);
rb->rd_pointer = pos + max;
return datasize;
}
int main()
{
Ringbuff *ring=(Ringbuff *)malloc(sizeof(Ringbuff));
u_char a[20]="abcdefghijklmno";
u_char buff[8]={0}; //定义循环buff
u_char mybuff[12]={0}; //用来存储从循环buff中读出的数据
rb_init (ring, buff, sizeof(buff)); //8
int w_res=0,r_res=0;
int i=0;
printf("--------------写------------\n");
w_res = rb_write (ring, a, 4); //先从a中写入四个字节到循环buff
printf("写入四个字节后,写指针所在位置:%d\n",ring->wr_pointer);
printf("当前空余空间:%d\n",rb_free_size(ring));
printf("当前数据所占空间:%d\n",rb_data_size(ring));
printf("\n");
printf("--------------读-------------\n");
r_res = rb_read (ring, mybuff, 3);
printf("第一次读取的数据:%s\n",mybuff);
printf("\n");
printf("------------第二次写---------------\n");
w_res = rb_write (ring, &a[4], 6);
printf("第二次写入6个字节,写指针所在位置:%d\n",ring->wr_pointer);
printf("读指针所在位置:%d\n",ring->rd_pointer);
printf("当前空余空间:%d\n",rb_free_size(ring));
printf("当前数据所占空间:%d\n",rb_data_size(ring));
// printf("%d\n",ring->wr_pointer);
printf("\n");
printf("-------------第二次读--------------\n");
r_res = rb_read (ring, &mybuff[3], 2);
// printf("%d \t %d\n",w_res,r_res);
printf("\n");
printf("第二次读到的数据:%s\n",mybuff);
return 0;
}