提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
要求
完成环形缓冲区函数库封装,生成成静态库和动态库,编写测试程序验证库文件,编写makefile实现编译,要求实现函数:
a、缓冲区初始化
b、往缓冲区写数据;
c、从缓冲区读数据;
d、计算缓冲区数据长度;
e、销毁缓冲区;
需要考虑到多个用户同时读写的情况,用到锁机制(互斥量)。
一、环形缓冲区
关于什么是环形缓冲区,这里就不介绍了,网上大量文章都会介绍,读几篇基本就了解了。
参考:
C语言实现环形缓冲区
环形缓冲区ring_buffer的c语言实现
【数据结构及算法】环形缓冲区(ring buffer)实现原理及代码实现(C语言)
不罗嗦,直接上代码。
二、环形缓冲区实现(C语言)
1. ringBuf.h
#ifndef _RINGBUF_H
#define _RINGBUF_H
#define read 0
#define write 1
#define quit 2
#define length 3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct ringBuf
{
char *buffer; /*缓冲区的数据*/
int size; /*缓冲区大小*/
int pRead; /*读指针,名义上的指针,只是为了记录位置而已*/
int pWrite; /*写指针,名义上的指针,只是为了记录位置而已*/
};
/*先不考虑互斥锁*/
/*先不考虑写覆盖和读重复问题,后续设计有效数据记录变量来解决*/
struct ringBuf *ringBufInit(struct ringBuf *ringBuffer,int size);
int ringBufRead(struct ringBuf *ringBuffer,char *readBuf,int readLength);
int ringBufWrite(struct ringBuf *ringBuffer,char *writeBuf,int writeLength);
int ringBufDataLen(struct ringBuf *ringBuffer);
void ringBufFree(struct ringBuf *ringBuffer);
int cmdHand(char *cmd);
#endif
2. ringBufInit.c
#include "ringBuf.h"
#include <stdlib.h>
/*环形缓冲区初始化函数*/
/*不使用全局变量,将环形缓冲区结构体返回*/
struct ringBuf *ringBufInit(struct ringBuf* ringBuffer,int size)
{
ringBuffer = (struct ringBuf*)malloc(sizeof(struct ringBuf));
if(NULL == ringBuffer)
{
printf("ringBuffer malloc error!\n");
exit(-1);
}
memset(ringBuffer,0,sizeof(struct ringBuf));
ringBuffer->buffer = (char*)malloc(size);
memset(ringBuffer->buffer,0,size);
ringBuffer->size = size;
ringBuffer->pRead = 0;
ringBuffer->pWrite = 0;
return ringBuffer;
}
3. ringBufRead.c
#include "ringBuf.h"
/*从环形缓冲区读数据*/
int ringBufRead(struct ringBuf *ringBuffer,char *readBuf,int readLength)
{
int pre = 0; //记录read指针到缓冲区尾端数据长度
int last = 0; //记录剩余数据长度,也就是缓冲区头部的部分数据
if(NULL == ringBuffer)
{
printf("ringBuffer is NULL,ringBuffer init error!\n");
exit(-1);
}
if(NULL == readBuf)
{
printf("readBuf is NULL,readBuf init error!\n");
exit(-1);
}
/*readLength超出缓冲区大小*/
/*可设置只读有效数据或直接报错*/
/*后续设计有效数据记录变量,防止读重复,同时也解决了readLength超缓冲区的问题*/
if(readLength > ringBuffer->size)
{
printf("readLength is too long!\n");
exit(-1);
}
if(readLength+ringBuffer->pRead <= ringBuffer->size)
{
/*readLength + pRead < size,要读的数据没有到达尾部*/
memcpy(readBuf,ringBuffer->buffer+ringBuffer->pRead,readLength);
}else
{
/*readLength + pRead > size,一部分数据在尾端,一部分在头端*/
int pre = ringBuffer->size - ringBuffer->pRead;
int last = readLength - pre;
memcpy(readBuf,ringBuffer->buffer+ringBuffer->pRead,pre);
memcpy(readBuf+pre,ringBuffer->buffer,last);
}
/*移动pRead指针*/
ringBuffer->pRead = (ringBuffer->pRead + readLength) % (ringBuffer->size);
return readLength; //后续要返回读有效数据长度
}
4. ringBufWrite.c
#include "ringBuf.h"
/*往环形缓冲区写数据*/
int ringBufWrite(struct ringBuf *ringBuffer,char *writeBuf,int writeLength)
{
int pre = 0; //记录write指针到缓冲区尾端长度
int last = 0; //记录剩余所需空间,也就是要往缓冲区头部写的部分空间
if(NULL == ringBuffer)
{
printf("ringBuffer is NULL,ringBuffer init error!\n");
exit(-1);
}
if(NULL == writeBuf)
{
printf("writeBuf is NULL,writeBuf init error!\n");
exit(-1);
}
/*writeLength超出缓冲区大小*/
/*可设置只写有效空间或直接报错*/
/*后续设计有效数据记录变量,防止写覆盖,同时也解决了writeLength超缓冲区的问题*/
if(writeLength > ringBuffer->size)
{
printf("writeLength is too long!\n");
exit(-1);
}
if(writeLength+ringBuffer->pWrite <= ringBuffer->size)
{
/*writeLength + pWrite < size 写空间足够,不用回到头部*/
memcpy(ringBuffer->buffer+ringBuffer->pWrite,writeBuf,writeLength);
}else
{
/*writeLength + pRead > size 一部分数据写在尾部,一部分数据写在头部*/
int pre = ringBuffer->size - ringBuffer->pWrite;
int last = writeLength - pre;
memcpy(ringBuffer->buffer+ringBuffer->pWrite,writeBuf,pre);
memcpy(ringBuffer->buffer,writeBuf+pre,last);
}
/*移动pWrite指针*/
ringBuffer->pWrite = (ringBuffer->pWrite + writeLength) % (ringBuffer->size);
return writeLength; //后续要返回写有效数据长度
}
5. ringBufDataLen.c
#include "ringBuf.h"
/*计算环形缓冲区数据长度*/
/*write指针可能在read指针前,也可能在read指针后*/
int ringBufDataLen(struct ringBuf *ringBuffer)
{
int dataLen = 0;
if(NULL == ringBuffer)
{
printf("ringBuffer is NULL!\n");
exit(-1);
}
if(ringBuffer->pWrite >= ringBuffer->pRead)
{
return (ringBuffer->pWrite - ringBuffer->pRead);
}else
{
return (ringBuffer->size - ringBuffer->pRead + ringBuffer->pWrite);
}
}
6. ringBufFree.c
#include "ringBuf.h"
/*释放环形缓冲区*/
void ringBufFree(struct ringBuf *ringBuffer)
{
if(NULL == ringBuffer)
{
printf("ringBuffer is NULL!\n");
exit(-1);
}
if(ringBuffer->buffer != NULL)
{
free(ringBuffer->buffer);
ringBuffer->buffer =NULL;
}
free(ringBuffer);
ringBuffer = NULL;
}
7. cmdHand.c
#include "ringBuf.h"
int cmdHand(char *cmd)
{
if(NULL == cmd)
{
printf("cmd is NULL!\n");
exit(-1);
}
if(strcmp("read",cmd) == 0)
{
return 0;
}
if(strcmp("write",cmd) == 0)
{
return 1;
}
if(strcmp("quit",cmd) == 0)
{
return 2;
}
if(strcmp("length",cmd) == 0)
{
return 3;
}
return 4;
}
8. main.c
#include "ringBuf.h"
int main()
{
/*暂时不考虑多用户同时操作的情况*/
/*暂时不考虑写覆盖和读重复问题,后续设计一个变量
* 用来监视有效数据长度*/
int bufLen = 16; //缓冲区大小
char *cmd = NULL;
int cmdNum = 0;
int strNum = 0; //要读取的字符数
int dataLen = 0; //缓冲区有效数据长度
char readBuf[24] = {
0}; //读缓存
char writeBuf[24] = {
0}; //写缓存
cmd = (char *)malloc(12);
memset(cmd,0,12);
struct ringBuf *ringBuffer = NULL;
ringBuffer = (struct ringBuf*)malloc(sizeof(struct ringBuf));
/*环形缓冲区初始化*/
ringBuffer = ringBufInit(ringBuffer,bufLen);
while(1)
{
/*输入指令,根据不同指令实现不同功能*/
printf("请输入指令(不要超过12字符):");
scanf("%s",cmd);
// printf("%s\n",cmd);
//
cmdNum = cmdHand(cmd);
switch(cmdNum)
{
/*从缓冲区读数据*/
case read:
printf("请输入需要读取的字符数:");
scanf("%d",&strNum);
memset(readBuf,0,sizeof(readBuf));
ringBufRead(ringBuffer,readBuf,strNum);
printf("读取结果:%s\n",readBuf);
break;
case write:
/*往缓冲区写数据*/
memset(writeBuf,0,sizeof(writeBuf));
printf("请输入要写入内容:");
scanf("%s",writeBuf);
ringBufWrite(ringBuffer,writeBuf,strlen(writeBuf));
printf("%s已写入\n",writeBuf);
break;
case quit:
/*销毁缓冲区*/
ringBufFree(ringBuffer);
printf("环形缓冲区已销毁!\n");
exit(0);
break;
case length:
/*计算缓冲区数据长度*/
dataLen = ringBufDataLen(ringBuffer);
printf("缓冲区的有效数据长度为:%d\n",dataLen);
break;
default:
printf("错误命令!\n");
break;
}
}
return 0;
}
9. Makefile
#main: main.c libringBufInit.a libringBufWrite.a libringBufRead.a libringBufDataLen.a libringBufFree.a libcmdHand.a
# gcc -o main main.c -L . -lringBufInit -lringBufWrite -lringBufRead -lringBufDataLen -lringBufFree -lcmdHand
#libringBufInit.a:
# gcc -c ringBufInit.c -o ringBufInit.o
# ar rcs libringBufInit.a ringBufInit.o
#libringBufWrite.a:
# gcc -c ringBufWrite.c -o ringBufWrite.o
# ar rcs libringBufWrite.a ringBufWrite.o
#libringBufRead.a:
# gcc -c ringBufRead.c -o ringBufRead.o
# ar rcs libringBufRead.a ringBufRead.o
#libringBufDataLen.a:
# gcc -c ringBufDataLen.c -o ringBufDataLen.o
# ar rcs libringBufDataLen.a ringBufDataLen.o
#libringBufFree.a:
# gcc -c ringBufFree.c -o ringBufFree.o
# ar rcs libringBufFree.a ringBufFree.o
#
#libcmdHand.a:
# gcc -c cmdHand.c -o cmdHand.o
# ar rcs libcmdHand.a cmdHand.o
#clean:
# rm *.o
# rm main
# rm *.a
main: main.c libringBufInit.so libringBufWrite.so libringBufRead.so libringBufDataLen.so libringBufFree.so libcmdHand.so
gcc -o main main.c -L . -lringBufInit -lringBufWrite -lringBufRead -lringBufDataLen -lringBufFree -lcmdHand
libringBufInit.so:
gcc -fPIC -shared ringBufInit.c -o libringBufInit.so
libringBufWrite.so:
gcc -fPIC -shared ringBufWrite.c -o libringBufWrite.so
libringBufRead.so:
gcc -fPIC -shared ringBufRead.c -o libringBufRead.so
libringBufDataLen.so:
gcc -fPIC -shared ringBufDataLen.c -o libringBufDataLen.so
libringBufFree.so:
gcc -fPIC -shared ringBufFree.c -o libringBufFree.so
libcmdHand.so:
gcc -fPIC -shared cmdHand.c -o libcmdHand.so
clean:
rm main
rm *.so