增加指针的LSB位但保留其余部分(硬编码的环形缓冲区大小)

时间:2014-08-18 19:58:57

标签: c

我尝试编写一个非常紧凑的环形缓冲区。缓冲区保存2 ^ X值(X:1-7)我需要的是增加X位(LSB)但保留其余变量。我有一个解决方案,但我不知道这是否有效(从未修改过指针地址)并且它不那么紧凑。知道如何改善这个吗?

        // hardcoded ringbuffersize for better ram usage
        // this frees us out, start, end, size variables
        // 7 == 128, 6 == 64
        #define LIGHTWEIGHT_RING_BUFFER_BITS 7
        #define LIGHTWEIGHT_RING_BUFFER_SIZE (1<<LIGHTWEIGHT_RING_BUFFER_BITS)
        // thatswhy we cant use 256 buffer size

        #define LIGHTWEIGHT_RING_BUFFER_DISABLED LIGHTWEIGHT_RING_BUFFER_SIZE+1
        // save new data
        *Buffer->In = Data;

        // save LSB bits
        uint8_t pointermask = Buffer->In;
        // discard all LSB bits
        Buffer->In >>= LIGHTWEIGHT_RING_BUFFER_BITS;
        Buffer->In <<= LIGHTWEIGHT_RING_BUFFER_BITS;
        // save the LSB bits + 1
        Buffer->In |= ++pointermask & (LIGHTWEIGHT_RING_BUFFER_SIZE - 1)

        Buffer->Count++;

2 个答案:

答案 0 :(得分:0)

这是一个简单的环形缓冲区实现的样子。环形缓冲区的大小由MASK确定。 MASK的值必须为2 n -1,其中n <= 8。对于256字节的环形缓冲区,您可以完全消除掩码。

#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>

#define MASK 7

typedef struct
{
    uint8_t head;
    uint8_t tail;
    uint8_t data[MASK + 1];
}
    stRingBuffer;

stRingBuffer ringBuffer = { 0, 0 };

// returns true if successful, false if the ring buffer is full
// the argument is the byte that is to be stored in the buffer
bool WriteToRingBuffer( stRingBuffer *buffer, uint8_t data )
{
    uint8_t nextHeadValue = (buffer->head + 1) & MASK;
    if ( nextHeadValue == buffer->tail )
        return( false );

    buffer->data[buffer->head] = data;
    buffer->head = nextHeadValue;
    return( true );
}

// returns a byte from the ring buffer, or 0 if the buffer is empty
// the caller is responsible for making sure the buffer is not empty before calling this function
uint8_t ReadFromRingBuffer( stRingBuffer *buffer )
{
    uint8_t data = 0;

    if ( buffer->tail != buffer->head )
    {
        data = buffer->data[buffer->tail];
        buffer->tail = (buffer->tail + 1) & MASK;
    }

    return( data );
}

// returns the number of items currently in the ring buffer
int itemCountInRingBuffer( stRingBuffer *buffer )
{
    return( (buffer->head - buffer->tail) & MASK );
}

int main( void )
{
    uint8_t data = 31;

    // move the head and tail to a non-zero location in the buffer for testing
    // this demonstrates proper handling of index wrap-around
    ringBuffer.head = 5;
    ringBuffer.tail = 5;

    // fill the buffer up
    while ( WriteToRingBuffer( &ringBuffer, data ) )
    {
        printf( "Wrote %u, buffer now has %d items\n", data, itemCountInRingBuffer( &ringBuffer ) );
        data++;
    }

    // empty the buffer out
    while ( ringBuffer.tail != ringBuffer.head )
    {
        data = ReadFromRingBuffer( &ringBuffer );
        printf( "Read %u, there are %d items remaining\n", data, itemCountInRingBuffer( &ringBuffer ) );
    }
}

请注意,如果您打算使用环形缓冲区在线程之间传递数据,或者从中断例程传递到后台代码,那么您需要使用适当的锁定机制,或者您需要成为无锁多线程的专家-threading。

答案 1 :(得分:0)

如果您要问的是如何以包装方式递增指针,答案非常简单。您需要将uint64_t类型转换替换为平台上指针的大小。如果所有低位都为零,则第二个语句包装指针。

p ++;
p -= ((uint64_t) p) & (LIGHTWEIGHT_RING_BUFFER_SIZE - 1) ?
    0 : LIGHTWEIGHT_RING_BUFFER_SIZE;

或者,再次用适当的替换类型转换

p = (uint8_t *) (((uint64_t) p & ~(LIGHTWEIGHT_RING_BUFFER_SIZE - 1)) |
                 (((uint64_t) p + 1) & (LIGHTWEIGHT_RING_BUFFER_SIZE - 1)));