写程序就是和逻辑和数据打交道,说的简单一点就是和数据打交道。说到数据,数据的存储当然是很重要的。
数据存储也是有一定的方法,在平常中,我们会用到int型来存储数据,或者bool型(C语言中没有,char型)来存储表示0,1的flag。有时候想想,如果只是简单的存储true和false的话,对于unsigned char型来说是否过于浪费了?信息论告诉我们,1bit数据就可以表示true和false,为什么不能将其存到1bit中?
那么,现在,我们开始将数据压缩。
如果有8个这样的数据,我们可以存在一个char型中,也就是uint8中。
bit0-bit7,每一个位都可以表示2个信息。那么就可以表示8种完全互不影响的标志。至于要表示什么,完全可以由“规则”来定。
假设,表示flag的数据很多?该如何做?
一个简单的方式:如果有n个标志,那么有
uint8 a[n];
这里,我们采用另外的一种方式。
uint8 a[m],其中m = n / 8;
那么,看到8倍这个数据,是不是一下子节省了很多?
对数据做计算的时候,"/"(除法)显然是要尽量避免的,虽然说是有那么简单,但是对于CPU来说可就不简单了。所以我们这里采用移位的方式。
即:m = n >> 3
那么如何去索引到某一个位呢?
很显然,用某一个0-7的数据将其存起来。
所以,去对某一个数据写数据需要两个信息,在第M个数组元素上,要写第X个bit位。很容易的会想到,封装一个函数,第一个参数为第几个数组元素,第二个参数为第几个位,第三个参数写入在该位上要写入的值。
即:
1 int func(int a,int b,int c) 2 { 3 if(c == 0) 4 { 5 gs_arg[a] &= ~(1 << b); 6 } 7 if(c == 1) 8 { 9 gs_arg[a] |= (1 << b); 10 } 11 }
以上这种方式,实现起来应该没有什么难度。不过,在对a值计算,对b值限定的时候,都会存在一系列的问题。那么我们何不采用另外的方式来解决这个问题呢?
对于上面提到的m = n >> 3应该表示没有异议吧。对于追求极致的人来说,为什么要把n的最后3位丢掉,这3位可以表示8个信息啊。
等等,你说什么?移位丢掉的数据可以表示8个信息,你的意思是可以表示0,1,2,3,4,5,6,7?这个问题是显然的。可以表示。
等等,我好像想到了什么!这样可以解决一些列的问题,不过也会带来另外的问题。
是的,可以通过丢弃的3位来表示写入数据的位数。用剩余的位的数据来表示数组的第几个元素。
那么,可以有如下的函数:
int func_md(int a,int b) { int ord; int s_bit; ord = a >> 3; s_bit = a & 0x07; s_move = 0x01 << s_bit; if(b == 0) { gs_arg[ord] &= ~s_move; //或者gs_arg[ord] &= s_move ^ 0xFF; } if(b == 1) { gs_arg[ord] |= s_move; } }
当然,为了满足很多规范,是需要做一些强制转换的限定的,同时传入的参数也存在一定的类型问题,这个在这里就不再那么规范了,表示意思即可。