1.getbitu函数
extern unsigned int getbitu(const unsigned char *buff, int pos, int len)
{
unsigned int bits=0;
int i;
for (i=pos;i<pos+len;i++)
bits=(bits<<1)+((buff[i/8]>>(7-i%8))&1u);
return bits;
}
解析:
(1)buff存放的是8位的字节,比如定义
unsigned char buff[]={0x8B,0x02,0x84,0x3E,0x56,0x26,0x28,0x50};
(2)算法:
比如getbitu(buff,43,3): 获取buff第43位置,长度为3.
a.定位置
位置是从0开始,小于32.
因为每个字节8为,43/8=5 余3,所以要找的位置是第6个字节0x26 即buff[i/8]
而0x26=b00100110=bit40~bit47) 从左往右,所以取的值是 001
b. 取bit
7-i%8=3或4或5
0x26依次往右移3位,4位,5位, 依次取出bit43,bit44,bit45, 通过bits<<1叠加
2.getbits函数
如果是负数,给bits添加符号,测试平台是linux 64bit 系统
return (int)(bits|(~0u<<len)); /* extend sign */ // 0xfffffff9
~0u=0xffffffff
~0u<<len=0xfffffff9
(int)(0xfffffff9): 因为强加了int类型,系统会把它当成负数直接输出0xfffffff9的补码,结果为-7
linux平台测试如下:
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
unsigned int getbitu(const unsigned char *buff, int pos, int len)
{
unsigned int bits=0;
int i;
for (i=pos;i<pos+len;i++){
bits=(bits<<1)+((buff[i/8]>>(7-i%8))&1u);
printf("i=%d,buff[%d/8]=0x%.02x\n",i,i,buff[i/8]);
}
return bits;
}
int getbits(const unsigned char *buff, int pos, int len)
{
unsigned int bits=getbitu(buff,pos,len);
if (len<=0||32<=len||!(bits&(1u<<(len-1)))) return (int)bits;
return (int)(bits|(~0u<<len)); /* extend sign */ // 0xfffffff9
}
void main()
{
//unsigned char buff[]={0x8B,0x02,0x84,0x3E,0x56,0x26};
unsigned char buff[]={0x8B,0x02,0x84,0x3E,0x56,0x26,0x28,0x50,0x00,0x6A,0xA8,0xA5,0xB6,0xDE,0xDB,0x14,0x7A,0xFB,0x08,0x49,0xEA ,0x39,0x2F,0x76, 0x00,0x00,0x02,0x15,0x1A,0x6A};
signed char sbuf[]={0x91,0x81};
unsigned char usbuf[]={0x91,0x81};
unsigned int uint,len,uval;
int sval;
//uint=getbitu(buff,43,3);
sval=getbits(sbuf,0,4);
uval=getbitu(usbuf,0,4);
//printf("unit=%.02x\n",unit);
printf("sval=%d,uval=%d\n",sval,uval);
}
结果为:sval=-7,uval=9
问题为啥sval=-7而不是9, 两者取出的都是第一个字节的高4位即1001但是sbuf里的数据是signed int有符号类型,所以取出的1001中最位1为符号位. 1为负号.所以此数为负数,值为它的补码:
~(1001)+1 ->b0110+1=b0111=7. 所以最后为-7
补充知识点:
计算机存放正负数规则:
正数: 原码存放
负数: 补码存放
原码: 比如一个正数为9,存放在计算机中为b00001001=0x09。 如果一个负数为-9,存放在计算器机
的是9的补码=原码取反+1=~(00001001)+1=11110110+1=11110111=0xF7
反码: 原码取反
补码: 原码取反+1