你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

c语言环形缓冲区的调试的无语一天。。

2021/11/25 4:56:17

代码设计过程中遇到bug

多的不说,先贴代码,重点关注at_queue_flush函数

void at_queue_flush(at_queue_t at_q) {
	uint8_t* p_temp = at_q->buf; 
	memset(at_q->buf, 0, at_q->size);
	memset(at_q, 0, sizeof(*at_q));
	at_q->buf = p_temp;
}

这是个环形缓冲区(下面简称rb),flush使其清空函数,目的是使得缓冲区内容全部清零,以及其他字段清零。代码是这么做的

  1. 先存rb 的缓冲区的地址,赋给p_temp
  2. 将缓冲区的内容通过memset清零。
  3. 将整一个rb通过memset清零,期望所有字段归零,此时buf为空指针。
  4. buf指向p_temp, 即指向之前保存的缓冲区地址

结果发现,调用了flush函数以后,再对其putchar是失败的!putchar返回0,由代码逻辑来看,这是缓冲区满造成的。但是紧随其后调用at_queue_debug,发现结果为

    |======at_queue_info======|
    buf=
    size=0
    read_mirror=0
    read_idx=0
    write_mirror=0
    write_idx=0
    */

这明显是初始状态,缓冲区为空,为什么会putchar失败呢?

真相令人震惊

文章写到这里,我也发现我自己的问题了,flush没有恢复rb->size这个数据,于是乎,size为0,当然不能够再putchar啦。
上面说是初始状态,这是不对的,因为根据代码逻辑,size=1024才是初始状态
ok,本篇文章为无营养文章,到此结束

环形缓冲区完整代码如下(可直接运行)

由于环形缓冲区用于进行at模块响应数据的接收,所以命名为at_queue了,不要在意- -

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>

#define at_queue_space_len(at_q) ((at_q)->size - at_queue_data_len(at_q))

struct at_queue_s {
  uint8_t* buf;		/* the buffer holding the data */ 
  uint16_t size;
	
  uint16_t read_mirror : 1;	/* 用于判断当read_idx==write_idx时,buf是空还是满 */
  uint16_t read_idx : 15;
  uint16_t write_mirror : 1;
  uint16_t write_idx : 15;
};
struct at_queue_s at_queue;
typedef struct at_queue_s *at_queue_t;
uint8_t at_queue_buf[1024];

typedef enum at_queue_state{
	AT_QUEUE_EMPTY,
	AT_QUEUE_FULL,
	AT_QUEUE_HALFFULL,
}AT_QUEUE_STATE;

static inline AT_QUEUE_STATE at_queue_get_state(at_queue_t at_q){
	if(at_q->read_idx == at_q->write_idx) {
		if(at_q->read_mirror == at_q->write_mirror)
			return AT_QUEUE_EMPTY;
		else 
			return AT_QUEUE_FULL;
	}
	return AT_QUEUE_HALFFULL;
}

// 获得缓冲区数据长度
uint16_t at_queue_data_len(at_queue_t at_q) {
	switch(at_queue_get_state(at_q)) {
		case	AT_QUEUE_EMPTY:
			return 0;
		case	AT_QUEUE_FULL:
			return at_q->size;
		case	AT_QUEUE_HALFFULL:
			if(at_q->write_idx > at_q->read_idx)
				return at_q->write_idx - at_q->read_idx;
			else
				return at_q->size - (at_q->read_idx - at_q->write_idx);
	};
	return at_q->size;
}

void at_queue_init(at_queue_t at_q, uint8_t* pool, uint16_t size) {
	assert(at_q != NULL);
	assert(size > 0);
	
	/* initialize read and write index */
    at_q->read_mirror = at_q->read_idx = 0;
    at_q->write_mirror = at_q->write_idx = 0;
	
	at_q->buf = pool;
	at_q->size = size;
}

/**
 * put a character into ring buffer
 */
size_t at_queue_putchar(at_queue_t at_q, const uint8_t ch) {
	assert(at_q != NULL);
	
  /* whether has enough space */
  if (!at_queue_space_len(at_q)){
    printf("in at_queue_putchar: AT_QUEUE_FULL!\r\n");
    return 0;	
  }
	 
	at_q->buf[at_q->write_idx] = ch;
	 
	/* flip mirror */
	if(at_q->write_idx == at_q->size-1) {
		at_q->write_mirror = ~at_q->write_mirror;
		at_q->write_idx = 0;
	} else {
		at_q->write_idx++;
	}
	 
	return 1;
}

void at_queue_flush(at_queue_t at_q) {
	uint8_t* p_temp = at_q->buf; 
    uint16_t size = at_q->size;
	memset(at_q->buf, 0, at_q->size);
	memset(at_q, 0, sizeof(*at_q));
	at_q->buf = p_temp;
    at_q->size = size;
}

static inline void at_queue_debug(at_queue_t at_q){
	printf("|======at_queue_info======|\r\n");
	printf("buf=%s\r\n",
		at_q->buf		/* the buffer holding the data */ 
	);
	printf("size=%u\r\nread_mirror=%u\r\nread_idx=%u\r\nwrite_mirror=%u\r\nwrite_idx=%u\r\n",
		at_q->size,
		at_q->read_mirror,	/* 用于判断当read_idx==write_idx时,buf是空还是满 */
		at_q->read_idx,
		at_q->write_mirror,
		at_q->write_idx
	);
}

int main()
{
    at_queue_t at_q = &at_queue;
    at_queue_init(at_q, at_queue_buf, sizeof(at_queue_buf));

    at_queue_debug(at_q);
    /*|======at_queue_info======|
    buf=
    size=1024
    read_mirror=0
    read_idx=0
    write_mirror=0
    write_idx=0
    */
    printf("at_q->buf addr = %p\r\n", at_q->buf);
	// at_q->buf addr = 0x404050
	
    at_queue_putchar(at_q, '\r');
	at_queue_putchar(at_q, '\n');
	at_queue_putchar(at_q, 'H');
	at_queue_putchar(at_q, 'E');
	at_queue_putchar(at_q, 'L');
	at_queue_putchar(at_q, 'L');
	at_queue_putchar(at_q, 'O');
	at_queue_putchar(at_q, '\r');
	at_queue_putchar(at_q, '\n');

    at_queue_debug(at_q);
    /*|======at_queue_info======|
    buf=
    HELLO

    size=1024
    read_mirror=0
    read_idx=0
    write_mirror=0
    write_idx=9
    */
   printf("at_q->buf addr = %p\r\n", at_q->buf);
   // at_q->buf addr = 0x404050

    at_queue_flush(at_q);

    at_queue_debug(at_q); 
    /*|======at_queue_info======|
    buf=
    size=0
    read_mirror=0
    read_idx=0
    write_mirror=0
    write_idx=0
    */
    printf("at_q->buf addr = %p\r\n", at_q->buf);
    // at_q->buf addr = 0x404050

    printf("%zu", at_queue_putchar(at_q, '\r'));
    // 输出0,说明putchar失败,putchar认为缓冲区已满
	at_queue_putchar(at_q, '\n');
	at_queue_putchar(at_q, 'H');
	at_queue_putchar(at_q, 'E');
	at_queue_putchar(at_q, 'L');
	at_queue_putchar(at_q, 'L');
	at_queue_putchar(at_q, 'O');
	at_queue_putchar(at_q, '\r');
	at_queue_putchar(at_q, '\n');

    at_queue_debug(at_q);
    /*显示居然是空!,期望的是和第二次debug结果一样
    |======at_queue_info======|
    buf=
    size=0
    read_mirror=0
    read_idx=0
    write_mirror=0
    write_idx=0
    */
   printf("at_q->buf addr = %p\r\n", at_q->buf);
   // at_q->buf addr = 0x404050
    return 0;
}