指针的3种含义
对于再熟悉不过指针来说,我们还是要理解为什么会有指针,以及指针存在的意义是什么。
指针一般有3种含义:
- 指明数据的位置 ,体现在指针的值 ,表示一个地址,这也是我们最容易理解的含义,即指针就是变量的地址。
- 表示数据类型的大小,虽然指针本身的值是一样大小的,但是不同类型的指针所表示的数据类型是不一样的。比如
int
指针表示4个字节为一组数据,体现在当使用指针的加减法时,会自动跳过4个字节。 - 表示数据被如何解释 ,虽然
float
指针和int
指针,都是4个字节,但是他们的解释完全不同,就体现在对指针解引用时,同样是4个字节,解析出来的数据是不一样的。
而void
指针它只有第一层含义,不能表示数据如何解释 ,以及也不能表示数据的大小,只是指明了数据的位置。
字节序
在计算机中,存储是按字节来为单位来寻址和存储的,比如一个int
类型数据,需要4个字节来存储,这种多字节数据一般都是被存储为连续的字节序列。
比如一个4字节的int
类型变量a
,其存储的起始字节地址为0x80901100
,则剩下的3个字节地址就分别为0x80901101
、0x80901102
和0x80901103
,这时问题就来了,a
的最低有效位可以存储在低地址,也可以存储在高地址中,这就引出了大端序和小端序。
大端序和小端序
比如一个int
类型的变量为0x12345678
,其中0x12
为最高有效位字节,0x78
为最低有效位字节 ,如果最高有效位存储在前面,则这种存储规则就是大端序,大端序就是我们日常的书写顺序。
假如低有效位存储在前面,这种存储方式就是小端序,我们日常使用的x86架构就是小端序。
0x12345678
采用大端序存储方式的形式:
0 | 1 | 2 | 3 |
---|---|---|---|
0x12 | 0x34 | 0x56 | 0x78 |
采用小端序存储的形式:
0 | 1 | 2 | 3 |
---|---|---|---|
0x78 | 0x56 | 0x34 | 0x12 |
这里我们一定要切记,我们日常使用的芯片架构采用的是小端序。
指针和字节序实践
记住前面所说的,指针的3层含义,其中不同类型的指针所对应的指针加减操作,以及解引用是不一样的,我们来看个例子:
C++
#include <stdio.h>
#include <arpa/inet.h>
/*
* 传入字节数组,打印字节的值以及其地址
*/
void stringToHex(char *string, unsigned int len) {
unsigned int loop = 0;
char* temp = string;
if (NULL == temp) {
printf("input param is null \n");
return;
}
for (loop = 0; loop < len; loop++) {
printf("address %p:0x%x \n", temp, *temp);
temp ++;
}
}
int main() {
printf("转换前\n");
int a = 0x12345678;
printf("a = 0x%x \n", a);
stringToHex((char*)&a, sizeof(int));
printf("转换后\n");
a = htonl(a);
printf("a = 0x%x \n", a);
stringToHex((char*)&a, sizeof(int));
return 0;
}
//输出结果:
转换前
a = 0x12345678
address 0x7fffe1415e84:0x78
address 0x7fffe1415e85:0x56
address 0x7fffe1415e86:0x34
address 0x7fffe1415e87:0x12
转换后
a = 0x78563412
address 0x7fffe1415e84:0x12
address 0x7fffe1415e85:0x34
address 0x7fffe1415e86:0x56
address 0x7fffe1415e87:0x78
我们来逐一分析:
- 在
stringToHex
方法中,我们使用printf
格式化打印结果,其中%p
表示打印地址,%x
表示按16进制打印。 a
的类型是int
,先使用&a
获取到变量a的地址,然后使用(char*)&a
把指针类型转成char
类型。这时我们应该知道,不论是int
类型指针还是char
类型指针,都是地址,只是在解引用时会取不同长度的字节来进行解析 。这里也就可以解释为什么变量是int
类型,我们却可以使用char
类型指针来指向它。- 从打印结果可以看出,
a
默认情况下,就是小端序存储的 ,0x78
为最低有效位,但是保存在前面。然后调用htonl
方法,该方法的原型以及描述:
vbnet
uint32_t htonl(uint32_t hostlong);
The htonl() function converts the unsigned integer hostlong from host byte order
to network byte order.
接收无符号int
类型数据,把主机字节序(当前为小端序)转成网络字节序(大端序),经过转换后,我们可以发现a的值变成了大端序形式。