Binary 位屏蔽缓冲区索引如何导致环绕
有人能用循环缓冲区索引来解释位屏蔽是如何工作的吗。特别是在以下代码中:Binary 位屏蔽缓冲区索引如何导致环绕,binary,embedded,Binary,Embedded,有人能用循环缓冲区索引来解释位屏蔽是如何工作的吗。特别是在以下代码中: #define USART_RX_BUFFER_SIZE 128 /* 2,4,8,16,32,64,128 or 256 bytes */ #define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 ) ISR(USART_RX_vect) { unsigned char data; unsigned char
#define USART_RX_BUFFER_SIZE 128 /* 2,4,8,16,32,64,128 or 256 bytes */
#define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 )
ISR(USART_RX_vect)
{
unsigned char data;
unsigned char tmphead;
/* Read the received data */
data = UDR0;
/* Calculate buffer index */
tmphead = ( USART_RxHead + 1 ) & USART_RX_BUFFER_MASK;
USART_RxHead = tmphead; /* Store new index */
if ( tmphead == USART_RxTail )
{
/* ERROR! Receive buffer overflow */
}
USART_RxBuf[tmphead] = data; /* Store received data in buffer */
}
我知道位掩蔽索引的结果是索引环绕;我的问题是为什么?另外,为什么“USART\u RX\u BUFFER\u SIZE”必须是2的幂
多谢各位
Joe要理解这一点,你必须理解一些二进制代码,你必须理解二进制操作 你可能知道,计算机中的所有东西都是以二进制存储的,即1和0的序列。这意味着从理论上讲,内存中的任何数据字符串都可以被视为数字。由于您的代码使用的是
char
s,因此我将重点介绍它们
在C语言中,char
s要么是有符号的,要么是无符号的,因此使用unsigned是很重要的。我不会讨论二的补码表示法,但我只想说,如果使用带符号的char
s,它将被破坏。字符是一个单字节,通常被认为是8位,如下所示:
00000000 -> 0
00001001 -> 9
基本上,每一位代表二的幂(我在这里首先使用MSB),所以第二个数字是2^1+2^3=1+8=9
。因此,您可以看到如何使用它来索引到数组中
按位操作对某些数据的各个位进行操作。在这种情况下,您使用的是二进制和(&
),应用二进制和的行为称为位掩蔽
data - 00101100
mask - 11110110
----------
result - 00101100
如您所见,仅当数据
和掩码
都有1时,结果的位才设置为1
现在回到我们的二进制表示。由于每一位是二的幂,二进制中的二的幂可以用0中的一个1表示
01000000 - 64
就像1000-1=999
,01000000-1=00111111
,其中00111111
是63
利用这一点,我们可以发现,在计算下一个索引时,我们执行以下操作:
(a + 1) & 00111111
如果a是(例如)10,那么我们得到
(00001010 + 1) = 00001011 (11)
00001011 & 00111111 = 00001011
所以掩蔽没有改变,但在63的情况下:
(00111111 + 1) = 01000000 (64)
01000000 & 00111111 = 00000000 (0)
因此,不要尝试索引到64(这是第65个元素,因此是一个错误),而是返回到开头
这就是为什么缓冲区大小必须是2的幂,如果不是,则掩码将无法正确计算,并且必须使用模(
%
)或比较,而不是位掩码。这一点很重要,因为位运算符速度非常快,因为在大多数处理器中它们通常只是一条指令,&
需要很少的周期。模可以是一条指令,但它可能是整数除法,在大多数平台上,这通常相当慢。比较需要几个指令、寄存器和至少一个跳转。要理解这一点,你必须理解一些二进制代码,你必须理解二进制操作
你可能知道,计算机中的所有东西都是以二进制存储的,即1和0的序列。这意味着从理论上讲,内存中的任何数据字符串都可以被视为数字。由于您的代码使用的是char
s,因此我将重点介绍它们
在C语言中,char
s要么是有符号的,要么是无符号的,因此使用unsigned是很重要的。我不会讨论二的补码表示法,但我只想说,如果使用带符号的char
s,它将被破坏。字符是一个单字节,通常被认为是8位,如下所示:
00000000 -> 0
00001001 -> 9
基本上,每一位代表二的幂(我在这里首先使用MSB),所以第二个数字是2^1+2^3=1+8=9
。因此,您可以看到如何使用它来索引到数组中
按位操作对某些数据的各个位进行操作。在这种情况下,您使用的是二进制和(&
),应用二进制和的行为称为位掩蔽
data - 00101100
mask - 11110110
----------
result - 00101100
如您所见,仅当数据
和掩码
都有1时,结果的位才设置为1
现在回到我们的二进制表示。由于每一位是二的幂,二进制中的二的幂可以用0中的一个1表示
01000000 - 64
就像1000-1=999
,01000000-1=00111111
,其中00111111
是63
利用这一点,我们可以发现,在计算下一个索引时,我们执行以下操作:
(a + 1) & 00111111
如果a是(例如)10,那么我们得到
(00001010 + 1) = 00001011 (11)
00001011 & 00111111 = 00001011
所以掩蔽没有改变,但在63的情况下:
(00111111 + 1) = 01000000 (64)
01000000 & 00111111 = 00000000 (0)
因此,不要尝试索引到64(这是第65个元素,因此是一个错误),而是返回到开头
这就是为什么缓冲区大小必须是2的幂,如果不是,则掩码将无法正确计算,并且必须使用模(%
)或比较,而不是位掩码。这一点很重要,因为位运算符速度非常快,因为在大多数处理器中它们通常只是一条指令,&
需要很少的周期。模可以是一条指令,但它可能是整数除法,在大多数平台上,这通常相当慢。比较需要几个指令、寄存器和至少一个跳转。约翰写道:
我支持关于模的评论,我们在我们的微计算机上发现了它 “a%=模数”比(a>b)长10-20倍 a/=模数;–约翰大学2012年8月3日17:01 但仍然存在除法:a/=模,因此效率与模运算相同,我假设..约翰写道:
我支持关于模的评论,我们在我们的微计算机上发现了它 “a%=模数”比(a>b)长10-20倍 a/=模数;–约翰大学2012年8月3日17:01
但仍然有除法:a/=模,因此效率和模运算相同,我想。很好的答案,我现在明白了!!谢谢