代码:
#include<stdio.h>
#include<malloc.h>
unsigned int get2byte(unsigned char *data){
return (data[0] << 8) | data[1];
}
int main(){
unsigned char *data;
data = (unsigned char *)malloc(sizeof(unsigned char));
data[0] = 10;
data[1] = 20;
printf("%u\n",get2byte(&data[0]));
return 0;
}
执行结果:
该程序的目的是将2Byte存储单元的内容组合成十六进制数计算结果。<< 8 相当于乘以 2^8, | 相当于加上。所以10 * 2^8 + 20 = 2580
通过get2byte函数的定义,可知其接收的参数是指针类型的。
考虑有一种场景,就像代码中那样,我们定义了一个指针data,指针指向的数据类型是无符号字符,并使用malloc函数为该指针分配了空间。使用data[0] = 10; 和 data[1] = 20;定义了该指针所指向的第0个单元和第1个单元的内容。
现在,假设有 data,data[0],&data[0],请问它们三者的区别是什么?
这里做出解释,data本身是一个指针,但是data[0]是data指针所指向的第0个存储单元的内容。也就是说,data是指针,data[0]是元素,如果在data[0]之前加上取地址符号&,那么&data[0]也是一个指针,并且&data[0]和data都是同一个指针的两种不同的表示形式。data[0] 和 *(data + 0)是相同的,因此,data[1] 和 *(data + 1)也是相同的,所以,data[0]和data[1]都仅仅代表指针所指向的存储单元内容。而如果加上取地址符号&,那么就是另外一种情况:如 &data[0]表示第0个单元的地址,&data[1]表示第1个单元的地址。
综上所述,get2byte函数传入的实参应当是&data[0]。
符号&有两种使用方式。一种是引用,一种是取地址。
当表示取地址时,将&写在一个变量的前面即可。
当表示引用时,有一定的规则:
1)当引用被创建时,它必须被初始化(指针则可以在任何时候被初始化),如int &a=y;int &q=12;
2)一旦一个引用被初始化为指向一个对象,它就不能改变为另一个对象的引用(指针则可以在任何时候指向另一个对象)
3)不可能有NULL引用。必须确保引用是和一块合法的存储单元关联。
下面的代码可以将内容放入内存单元中,并且可以取出来。
#include<stdio.h>
#include<malloc.h>
#define ROUND8(x) (((x)+7)&~7)
typedef unsigned char u8;
typedef unsigned int u32;
//之所以定义 put2byte和get2byte是因为如果一次操作的数据只占据两个字节,那么可以使用指向无符号字符的指针类型u8来作为载体,很方便地对一字节的内存单元进行操作。
#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
#define get2byte(x) ((x)[0]<<8 | (x)[1])
int main(){
u8 *pIter;
u8 *pEnd;
u32 nSize;
pIter= (u8 *)malloc(sizeof(u8));
pIter[0] = 0x8a;
pIter[1] = 0x78;
//sqlite中计算可变长整数
nSize = *pIter;
if( nSize>=0x80 ){
pEnd = &pIter[8];
nSize &= 0x7f;
do{
nSize = (nSize<<7) | (*++pIter & 0x7f);
}while( *(pIter)>=0x80 && pIter<pEnd );
}
pIter++;
return 0;
}