最近笔者一直在做JPEG的解码工作,发现用完全使用哈夫曼树进行解码比较费时,而使用表结构存储编码和值的对应关系比较快捷,但是也存在比较难处理的地方,比如解码工作通常是以位为单位的操作,这里必然会涉及到移位操作,而笔者之前对位的操作很少,经验很欠缺,经过这次历练终于发现了一个自己曾经忽视的东西,那就是C/C++中的移位操作容易出错的情况。
1、什么样的数据类型可以直接移位
char、short、int、long、unsigned char、unsigned short、unsigned int、unsigned long都可以进行移位操作,而double、float、bool、long double则不可以进行移位操作。
2、有符号数据类型的移位操作
对于char、short、int、long这些有符号的数据类型:
- 对负数进行左移:符号位始终为1,其他位左移
- 对正数进行左移:所有位左移,即 <<,可能会变成负数
- 对负数进行右移:取绝对值,然后右移,再取相反数
- 对正数进行右移:所有位右移,即 >>
3、无符号数据类型的移位操作
对于unsigned char、unsigned short、unsigned int、unsigned long这些无符号数据类型:
没有特殊要说明的,使用<< 和 >> 操作符就OK了
结束语
8086 中存在逻辑移位、算术移位,而C\C++中的移位似乎既不是逻辑移位,也不是算术移位。
比如-1,我们若对它右移1位,C的结果仍旧是-1,事实上无论右移多少位始终是-1,逻辑移位得到的结果(8位表示)应该是-128,所以这点要注意
例子:
1.将 13800138000 转为 91 68 31 08 10 83 00 F0 //91为+ 68国家号 不够位长以F补
unsigned char *tt = new unsigned char[12];
strcpy((char*)tt,"13800138000");
tt[11] = 0xFF;
unsigned char *ss = new unsigned char[6];
cout << (tt[11]<<4) << endl;
memset(ss,0xFF,6);
int k=0;
for(int i=0; i<12; i=i+2)
{
ss[k++] = (tt[i+1]<<4)+(tt[i]&0x0F);
}
2. 将 整形 转为 3位字节型16进制,如将 整型 888 转为 16进制 00 03 78(Debug下有效,Release下无效) char param[4] = {0};
int iParamLen = 888;
param[0] = iParamLen >> 16;
param[1] = ((iParamLen >> 8) << 32) >> 32;
param[2] = (iParamLen << 32) >> 32;
反之
char param[4] = {0x00,0x03,0x78};
int ii1 = 0;
ii1 = param[0];
ii1 =ii1 << 8;
ii1 = ii1 | param[1];
ii1 =ii1 << 8;
ii1 = ii1 | param[2];