缓冲区ringbuffer

 

1:背景介绍:
在日常业务开发中,使用缓冲区进行临时存储的业务场景也比较多,如tcp每个连接底层都维持一个发送缓冲区和接收缓冲区。

 

实现一个ringbuffer,做代码备用。(可以考虑如何对ringbuffer进行扩大?)

//实现ringbuffer,其实就是申请一块内存,对塞入数据和取出数据位置分别进行管理
typedef struct RINGBUFF_T{
    void * data;
    unsigned int size;
    unsigned int read_pos;   //数据起始位置
    unsigned int write_pos;  //数据终止位置
}ringbuffer_t;

2:测试代码:
这里的代码是我为了测试,实现一个ringbuffer进行管理。

这里只考虑了单线程的逻辑实现,多线程需要适配一下。。。

这里在取数据时,有一定的设计,考虑取一个包的数据(可以自己适配调整)。

2.1:my_ringbuffer.h
#ifndef __RINGBUFFER_H_
#define __RINGBUFFER_H_

typedef struct RINGBUFF_T{
    void * data;
    unsigned int size;
    unsigned int read_pos;   //数据起始位置
    unsigned int write_pos;  //数据终止位置
}ringbuffer_t;

//创建ringbuffer
ringbuffer_t * ringbuffer_create(unsigned int size);
//销毁ringbuffer
void ringbuffer_destroy(ringbuffer_t * ring_buffer);

//往ringbuffer中存数据 写入
int ringbuffer_put(ringbuffer_t * ring_buffer, const char* buffer, unsigned int len);
//判断是否是完整的数据  然后进行处理
int ringbuffer_get_len(ringbuffer_t *ring_buffer);
//依赖ringbuffer_get_len 返回值申请内存,取出ring_buffer中的数据
int ringbuffer_get(ringbuffer_t * ring_buffer, char * buffer, unsigned int len);

//基本接口 外部基本不用,但是函数内部有使用
//重置缓冲区
void ringbuffer_reset(ringbuffer_t * ring_buffer);
//ringbuffer已经使用的内存空间的大小
int ringbuffer_use_len(ringbuffer_t * ring_buffer);
//ringbuffer没有使用的内存的大小
int ringbuffer_space_len(ringbuffer_t * ring_buffer);

//基本的判空和判满接口
int ringbuffer_isempty(ringbuffer_t * ring_buffer);
int ringbuffer_isfull(ringbuffer_t * ring_buffer);

// int get_ringbuffer_size(ringbuffer_t * ring_buffer);
#endif //__RINGBUFFER_H_

2.2:my_ringbuffer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "my_ringbuffer.h"

static inline __attribute__((const))
int is_power_of_2(unsigned long n)
{
    return (n != 0 && ((n & (n - 1)) == 0));
}

static unsigned long roundup_power_of_two(unsigned long n)
{
    if((n & (n-1)) == 0)
        return n;
    
    unsigned long maxulong = (unsigned long)((unsigned long)~0);
    unsigned long andv = ~(maxulong&(maxulong>>1));

    while((andv & n) == 0)
        andv = andv>>1;

    return andv<<1;
}

//创建ringbuffer 
ringbuffer_t * ringbuffer_create(unsigned int size)
{
    //对入参进行校验 并且是2的次方
    if (!is_power_of_2(size)) {
        size = roundup_power_of_two(size);
    }

    ringbuffer_t * ring_buffer;
    ring_buffer = (ringbuffer_t*)malloc(sizeof(*ring_buffer));
    if(ring_buffer == NULL)
    {
        printf("create ringbuffer error \n");
        return NULL;
    }

    ring_buffer->data = (void*)malloc(size);
    if(ring_buffer->data == NULL)
    {
        printf("create ringbuffer data error \n");
        free(ring_buffer);
        return NULL;
    }

    ring_buffer->size = size;
    ring_buffer->read_pos = 0;
    ring_buffer->write_pos = 0;
    return ring_buffer;
}

//销毁ringbuffer
void ringbuffer_destroy(ringbuffer_t * ring_buffer)
{
    if(ring_buffer)
    {
        if(ring_buffer->data)
        {
            free(ring_buffer->data);
            ring_buffer->data = NULL;
        }
        free(ring_buffer);
        ring_buffer = NULL;
    }
}

//往ringbuffer中存数据 写入
int ringbuffer_put(ringbuffer_t * ring_buffer, const char* buffer, unsigned int len)
{
    if(ring_buffer->write_pos >=ring_buffer->read_pos &&(len <(ring_buffer->size - ring_buffer->write_pos +ring_buffer->read_pos)))
    {
        //进行拷贝
        if(ring_buffer->size - ring_buffer->write_pos >len)
        {
            memcpy(ring_buffer->data + ring_buffer->write_pos, buffer, len);
            ring_buffer->write_pos += len;
        }else
        {
            unsigned int right_space_len = ring_buffer->size - ring_buffer->write_pos;
            memcpy(ring_buffer->data + ring_buffer->write_pos, buffer, right_space_len);
            memcpy(ring_buffer->data, buffer+right_space_len, len - right_space_len);
            ring_buffer->write_pos = len - right_space_len;
        }
        return 0;
    }

    if(ring_buffer->write_pos <ring_buffer->read_pos && (ring_buffer->read_pos - ring_buffer->write_pos) >len)
    {
        memcpy(ring_buffer->data + ring_buffer->write_pos, buffer, len);
        ring_buffer->write_pos += len;
        return 0;
    }

    return -1;
}

//判断是否是完整的数据  然后进行处理
int ringbuffer_get_len(ringbuffer_t *ring_buffer)
{
    //对ringbuffer中的数据做判断解析  如果是完整的数据  则提取出去
    if(ringbuffer_use_len(ring_buffer) < strlen("FFFF0D0A<header><tail>0D0AFEFE"))
    {
        printf("ringbuffer data is error [%d], [%ld]\n", ringbuffer_use_len(ring_buffer),  strlen("FFFF0D0A<header><tail>0D0AFEFE"));
        return -1;
    }
    //判断是否是终结的字段
    const char* end_str = "<tail>0D0AFEFE";
    char check_end_str[20] = {0};
    if(ring_buffer->write_pos >strlen(end_str))
    {
        memcpy(check_end_str, ring_buffer->data+ring_buffer->write_pos - (strlen(end_str)),  strlen(end_str));
    }else
    {
        unsigned int left_len = ring_buffer->write_pos;
        memcpy(check_end_str, ring_buffer->data +ring_buffer->size - (strlen(end_str) - left_len), ring_buffer->size - (strlen(end_str) - left_len));
        memcpy(check_end_str + (strlen(end_str) - left_len), ring_buffer->data, left_len);
    }
    printf("get check_end_str is %s \n", check_end_str);


    char * ret_addr = strstr(check_end_str, end_str);
    if(ret_addr == NULL)
    {
        return -1;
    }

    if(check_end_str - ret_addr != 0)
    {
        printf("DDDDD :why end string is error");
        return -1;
    }

    return ringbuffer_use_len(ring_buffer);
}

//从ringbuffer中取数据做处理, 判断接收到的字符是否是终结符号,就可以去做处理
//取完数据后重置ringbuffer的位置  读取
int ringbuffer_get(ringbuffer_t * ring_buffer, char * buffer, unsigned int len)
{
    //这里建立在ringbuffer_get_len 的基础上,传入入参,取出数据
    int data_len = ringbuffer_use_len(ring_buffer);
    if(data_len >= len)
    {
        printf("para buffer is not enough space \n");
        return -1;
    }

    if(ring_buffer->write_pos >ring_buffer->read_pos )
    {
        printf("get data from ringbuffer len: [%d] \n", ring_buffer->write_pos - ring_buffer->read_pos);
        memcpy(buffer, ring_buffer->data + ring_buffer->read_pos, data_len);
    }else
    {
        memcpy(buffer, ring_buffer->data+ring_buffer->read_pos, ring_buffer->size - ring_buffer->read_pos);
        memcpy(buffer+ring_buffer->size - ring_buffer->read_pos, ring_buffer->data, data_len - (ring_buffer->size - ring_buffer->read_pos));
    }

    ring_buffer->write_pos = 0;
    ring_buffer->read_pos = 0;
    return 0;
}

//直接从socket中读数据放入ringbuffer中也可以
int ringbuffer_get_from_dev()
{
    return 0;
}
//直接从ringbuffer中取数据用socket进行发送
int ringbuffer_put_to_dev()
{
    return 0;
}

void ringbuffer_reset(ringbuffer_t * ring_buffer)
{
    ring_buffer->read_pos = ring_buffer->write_pos = 0;
}

int ringbuffer_use_len(ringbuffer_t * ring_buffer)
{
    if(ring_buffer->write_pos >= ring_buffer->read_pos)
    {
        return ring_buffer->write_pos-ring_buffer->read_pos;
    }

    return ring_buffer->write_pos + ring_buffer->size - ring_buffer->read_pos;
}

int ringbuffer_space_len(ringbuffer_t * ring_buffer)
{
    if(ring_buffer->write_pos >= ring_buffer->read_pos)
    {
        return ring_buffer->read_pos +(ring_buffer->size - ring_buffer->write_pos);
    }

    return ring_buffer->read_pos - ring_buffer->write_pos;
}

int ringbuffer_isempty(ringbuffer_t * ring_buffer)
{
    return ringbuffer_use_len(ring_buffer) == 0? 0 :-1;
}

int ringbuffer_isfull(ringbuffer_t * ring_buffer)
{
    return ringbuffer_space_len(ring_buffer) == 0? 0 :-1;
}

// int get_ringbuffer_size(ringbuffer_t * ring_buffer)
// {
//     return ring_buffer->size;
// }

2.3:my_ringbuffer_test.c
/************************************************
info: 对ringbuffer的封装做简单的测试
data: 2022/02/10
author: hlp
************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tcp_ringbuffer.h"

int main()
{
    //申请一个ringbuffer 
    ringbuffer_t * ringbuff = ringbuffer_create(128);
    printf("ringbuffer_create size is : %d \n", ringbuff->size);
    printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));
    printf("ringbuffer isfull [%d] \n", ringbuffer_isfull(ringbuff));
    printf("ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));
    ringbuffer_destroy(ringbuff);
    //判断基本的条件
    ringbuff = ringbuffer_create(129);
    printf("ringbuffer_create size is : %d \n", ringbuff->size);
    printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));
    printf("ringbuffer isfull [%d] \n", ringbuffer_isfull(ringbuff));
    printf("ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));
    ringbuffer_destroy(ringbuff);

    //给ringbuff中塞入一定的数据查看相关的基本信息
    ringbuff = ringbuffer_create(129);
    const char* str_data = "FFFF0D0A<header><tail>0D0AFEFE";
    //给ringbuffer中塞入一定的数据,进行获取查看
    ringbuffer_put(ringbuff, str_data, strlen(str_data));
    printf("set data size is : %lu, ringbuff size is %d \n", strlen(str_data), ringbuff->size);
    printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));
    printf("ringbuffer isfull [%d] \n", ringbuffer_isfull(ringbuff));
    printf("ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));
    int data_len = ringbuffer_get_len(ringbuff);
    if(data_len == -1)
    {
        printf("error of ringbuff data \n");
    }else
    {
        printf("ringbuff data len is %d \n", data_len);
    }
    char * data_exec;
    data_exec = (char*)malloc(data_len +1);
    memset(data_exec, 0, data_len +1);
    printf("sizeof data_exec is %lu \n", sizeof(data_exec));
    ringbuffer_get(ringbuff, data_exec, data_len +1);
    printf("ringbuff get data is :%s \n",data_exec);
    printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));
    printf("ringbuffer isfull [%d] \n", ringbuffer_isfull(ringbuff));
    printf("ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));
    ringbuffer_destroy(ringbuff);
    if(data_exec !=NULL)
    {
        free(data_exec);
        data_exec = NULL;
    }


    printf("******************test of more package check***********************\n");
    const char* data_str_test = "FFFF0D0A<header><tail>0D0AFEFE";
    const char* data_str_test1 = "FFFF0D0A<header>111<tail>0D0AFEFE";
    const char* data_str_test2 = "FFFF0D0A<header>222<tail>0D0AFEFE";
    const char* data_str_test3 = "FFFF0D0A<header><tail>0D0AFEFE";
    const char* data_str_test4 = "FFFF0D0A<header><tail>0D0AFEFE";
    const char* data_str_error = "FFFF0D0A<header>test error";
    //试着塞多个数据 能取出来吗?
    ringbuff = ringbuffer_create(129);
    ringbuffer_put(ringbuff, data_str_test, strlen(data_str_test));
    printf("put one data. ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("put one data.  ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));
    ringbuffer_put(ringbuff, data_str_test1, strlen(data_str_test1));
    printf("put two data. ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("put two data.  ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));
    ringbuffer_put(ringbuff, data_str_test2, strlen(data_str_test2));
    printf("put three data. ringbuffer used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("put three data.  ringbuffer space len is [%d] \n", ringbuffer_space_len(ringbuff));
    printf("ringbuffer is not empty [%d] \n", ringbuffer_isempty(ringbuff));
    printf("ringbuffer is not full [%d] \n", ringbuffer_isfull(ringbuff));
    int test_get_len = ringbuffer_get_len(ringbuff);
    if(test_get_len == -1)
    {
        printf("error of ringbuff data \n");
    }else
    {
        printf("get ringbuff has data len is %d \n", test_get_len);
    }
    data_exec = (char*)malloc(test_get_len +1);
    memset(data_exec, 0, test_get_len +1);
    ringbuffer_get(ringbuff, data_exec, test_get_len +1);
    printf("ringbuff get data is :%s \n",data_exec);
    printf("get all data used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("get all data space len is [%d] \n", ringbuffer_space_len(ringbuff));
    printf("ringbuffer isempty [%d] \n", ringbuffer_isempty(ringbuff));
    printf("ringbuffer is not full [%d] \n", ringbuffer_isfull(ringbuff));
    ringbuffer_destroy(ringbuff);
    if(data_exec !=NULL)
    {
        free(data_exec);
        data_exec = NULL;
    }

    ringbuff = ringbuffer_create(129);
    ringbuffer_put(ringbuff, data_str_test, strlen(data_str_test));
    ringbuffer_put(ringbuff, data_str_error, strlen(data_str_error));
    test_get_len = ringbuffer_get_len(ringbuff);
    if(test_get_len == -1)
    {
        printf("error of ringbuff data \n");
    }else
    {
        printf("get ringbuff has data len is %d \n", test_get_len);
    }
    ringbuffer_put(ringbuff, data_str_test, strlen(data_str_test));
    test_get_len = ringbuffer_get_len(ringbuff);
    if(test_get_len == -1)
    {
        printf("error of ringbuff data \n");
    }else
    {
        printf("get ringbuff has data len is %d \n", test_get_len);
    }
    data_exec = (char*)malloc(test_get_len +1);
    memset(data_exec, 0, test_get_len +1);
    ringbuffer_get(ringbuff, data_exec, test_get_len +1);
    printf("ringbuff get data is :%s \n",data_exec);
    printf("get all data used len is [%d] \n",ringbuffer_use_len(ringbuff));
    printf("get all data space len is [%d] \n", ringbuffer_space_len(ringbuff));
    ringbuffer_destroy(ringbuff);
    if(data_exec !=NULL)
    {
        free(data_exec);
        data_exec = NULL;
    }
    //根本不会有write追到read的场景,除非这里的设计做成不是全部取出,或者多线程处理
    printf("******************* check \n");

    return 0;
}

3:运行结果
这里我使用的gcc进行编译,没有用makefile

这里是为了符合特定的业务格式,有“FFFF0D0A

”和“0D0AFEFE”进行标识的数据才认为是一个完整的数据。
写这个测试代码主要是为了针对tcp接收缓冲区业务处理考虑的。

hlp@ubuntu:~/220107/0:test_ringbuffer_tcp_Stickybag$ ./ringbuffer 
ringbuffer_create size is : 128 
ringbuffer isempty [0] 
ringbuffer isfull [-1] 
ringbuffer used len is [0] 
ringbuffer space len is [128] 
ringbuffer_create size is : 256 
ringbuffer isempty [0] 
ringbuffer isfull [-1] 
ringbuffer used len is [0] 
ringbuffer space len is [256] 
set data size is : 30, ringbuff size is 256 
ringbuffer isempty [-1] 
ringbuffer isfull [-1] 
ringbuffer used len is [30] 
ringbuffer space len is [226] 
get check_end_str is <tail>0D0AFEFE 
ringbuff data len is 30 
sizeof data_exec is 8 
get data from ringbuffer len: [30] 
ringbuff get data is :FFFF0D0A<header><tail>0D0AFEFE 
ringbuffer isempty [0] 
ringbuffer isfull [-1] 
ringbuffer used len is [0] 
ringbuffer space len is [256] 
******************test of more package check***********************
put one data. ringbuffer used len is [30] 
put one data.  ringbuffer space len is [226] 
put two data. ringbuffer used len is [63] 
put two data.  ringbuffer space len is [193] 
put three data. ringbuffer used len is [96] 
put three data.  ringbuffer space len is [160] 
ringbuffer is not empty [-1] 
ringbuffer is not full [-1] 
get check_end_str is <tail>0D0AFEFE 
get ringbuff has data len is 96 
get data from ringbuffer len: [96] 
ringbuff get data is :FFFF0D0A<header><tail>0D0AFEFEFFFF0D0A<header>111<tail>0D0AFEFEFFFF0D0A<header>222<tail>0D0AFEFE 
get all data used len is [0] 
get all data space len is [256] 
ringbuffer isempty [0] 
ringbuffer is not full [-1] 
get check_end_str is der>test error 
error of ringbuff data 
get check_end_str is <tail>0D0AFEFE 
get ringbuff has data len is 86 
get data from ringbuffer len: [86] 
ringbuff get data is :FFFF0D0A<header><tail>0D0AFEFEFFFF0D0A<header>test errorFFFF0D0A<header><tail>0D0AFEFE 
get all data used len is [0] 
get all data space len is [256] 
******************* check

原文链接:https://blog.csdn.net/yun6853992/article/details/122913568

“RingBuffer.h”

注意是head指向了读区域,tail指向了写区域!

注意是head指向了读区域,tail指向了写区域!

注意是head指向了读区域,tail指向了写区域!

typedef struct {
    size_t rb_capacity;     //缓冲区容量
    char  *rb_head;         //用于读出的指针
    char  *rb_tail;         //用于写入的指针
    char  rb_buff[256];     //缓冲区实体
}RingBuffer;

下面分析他的几个函数:

“RingBuffer.c”

//用来比较最小值的宏
#define min(a, b) (a)<(b)?(a)

b)

//新建RingBuffer,给成员赋值
//MAX_RINGBUFFER_LEN 这个宏,被定义为"P0数据最大长度"的2倍
//head/tail  两个指针,都指向缓冲区实体(数组rb_buff)的首地址
void rb_new(RingBuffer* rb)
{
    rb->rb_capacity = MAX_RINGBUFFER_LEN; //capacity;
    rb->rb_head     = rb->rb_buff;
    rb->rb_tail     = rb->rb_buff;
};

获得缓冲区总容量Capacity:

size_t     rb_capacity(RingBuffer *rb)
{
    return rb->rb_capacity;
}

获得缓冲区可读区域,返回可读区域大小:

三种情况:

1、head与tail都指向同一个地方时,可读区域大小为0【这种情况只会在缓冲区还未使用时出现,

开始使用之后,不会出现head/tail重合的现象,即tail永远不会等于head,否则head指向的数据还未读走就被覆盖了!】

2、head < tail  ,说明tail没有写到缓冲区末尾,从缓冲区开头重新开始。可读的区域自然为(tail - head)

3、head > tail  ,说明tail已经从缓冲区末尾写完,并从开头处重新准备写了。

插入图片给大家看看:

rb_buff是数组名,因此可以作为缓冲实体首地址的指

size_t     rb_can_read(RingBuffer *rb)
{
    if (rb->rb_head == rb->rb_tail) return 0;
    if (rb->rb_head < rb->rb_tail) return rb->rb_tail - rb->rb_head;
    return rb_capacity(rb) - (rb->rb_head - rb->rb_tail);
}

获得可写区域大小,就可以用总容量 减去 可读区域大小来计算了:

size_t     rb_can_write(RingBuffer *rb)
{
    return rb_capacity(rb) - rb_can_read(rb);
}

读数据,从head指向的地址开始,读到data指向的地址处,读count个数据。返回读的个数

三种情况:

1、head < tail  ,此时要从count 和"可读区域大小"中选一个较小的值,作为读操作的次数。避免了count 大于“可读区域”的错误。

2、head > tail  且 count 的个数 小于“从head到缓冲区末尾的数据个数”图中蓝色。直接复制内存,再修改head 指针即可。

3、head > tail  且 count 的个数 大于“从head到缓冲区末尾的数据个数”。

此时,先把从head到缓冲区末尾的值蓝色复制到data处,再把剩余的绿色复制过去。注意两个值:copy_sz 和*(data + copy_sz)如图

这种情况下,问题来了,要是绿色的区域超过了tail 怎么办?:)

所以,应该加了一个判断,这个在写操作中做了,但这里没做。即要读的个数count 要小于可读区域的大小。

不然会出现head > tail 但head 指向的数据以及head 后边的数据又不是有效数据,这个问题。

代码:

size_t     rb_read(RingBuffer *rb, void *data, size_t count)
{
    if (rb->rb_head < rb->rb_tail)
    {
        int copy_sz = min(count, rb_can_read(rb));
        memcpy(data, rb->rb_head, copy_sz);
        rb->rb_head += copy_sz;
        return copy_sz;
    }
    else
    {
        if (count < rb_capacity(rb)-(rb->rb_head - rb->rb_buff))
        {
            int copy_sz = count;
            memcpy(data, rb->rb_head, copy_sz);
            rb->rb_head += copy_sz;
            return copy_sz;
        }
        else
        {
            int copy_sz = rb_capacity(rb) - (rb->rb_head - rb->rb_buff);
            memcpy(data, rb->rb_head, copy_sz);
            rb->rb_head = rb->rb_buff;   
            copy_sz += rb_read(rb, (char*)data+copy_sz, count-copy_sz); 
            return copy_sz;
        }
    }
}

 

 

写数据,把数据从data指向的地址,写到tail 指向的地址,写count个。返回写的个数。

这里进来直接判断,要写入的内容大小 要小于可写区域大小,防止造成数据覆盖。写入合法。

下面写入分了三种情况:

1、2 需要计算tail_avail_sz,这个值为tail 到缓冲区末尾的数据区域大小。

1、head < tail  ,count < tail_avail_sz  。直接复制内容。假如tail 到了缓冲区末尾,让tail 回到缓冲区首地址。

2、head < tail  ,count > tail_avail_sz  。先写入 tail_avail_sz 个数据,tail 回到缓冲区首地址,再写入剩余的部分。

3、head > tail  ,这种情况最简单,由于已经做了写入合法判断,所以直接复制内容,修改tail 即可。

代码:

size_t     rb_write(RingBuffer *rb, const void *data, size_t count)
{
    if (count >= rb_can_write(rb)) 
			return -1;
    
    if (rb->rb_head <= rb->rb_tail)  
    {
        int tail_avail_sz = rb_capacity(rb) - (rb->rb_tail - rb->rb_buff);
        if (count <= tail_avail_sz)
        {
            memcpy(rb->rb_tail, data, count);
            rb->rb_tail += count;
            if (rb->rb_tail == rb->rb_buff+rb_capacity(rb))
                rb->rb_tail = rb->rb_buff;
            return count;
        }
        else
        {
            memcpy(rb->rb_tail, data, tail_avail_sz);
            rb->rb_tail = rb->rb_buff;
            
            return tail_avail_sz + rb_write(rb, (char*)data+tail_avail_sz, count-tail_avail_sz);
        }
    }
    else
    {
        memcpy(rb->rb_tail, data, count);
        rb->rb_tail += count;
        return count;
    }
}

对于源程序中的,指针不为NULL判断,其实是必须要加上的,不知道为什么,我下载的代码,这些部分都被注释掉了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340