指针与字节序

指针的3种含义

对于再熟悉不过指针来说,我们还是要理解为什么会有指针,以及指针存在的意义是什么。

指针一般有3种含义:

  1. 指明数据的位置 ,体现在指针的值 ,表示一个地址,这也是我们最容易理解的含义,即指针就是变量的地址。
  2. 表示数据类型的大小,虽然指针本身的值是一样大小的,但是不同类型的指针所表示的数据类型是不一样的。比如int指针表示4个字节为一组数据,体现在当使用指针的加减法时,会自动跳过4个字节。
  3. 表示数据被如何解释 ,虽然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

我们来逐一分析:

  1. 在stringToHex方法中,我们使用printf格式化打印结果,其中%p表示打印地址,%x表示按16进制打印。
  2. a的类型是int,先使用&a获取到变量a的地址,然后使用(char*)&a把指针类型转成char类型。这时我们应该知道,不论是int类型指针还是char类型指针,都是地址,只是在解引用时会取不同长度的字节来进行解析 。这里也就可以解释为什么变量是int类型,我们却可以使用char类型指针来指向它。
  3. 从打印结果可以看出,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的值变成了大端序形式。

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
weilx12343 天前
C++笔记-文件IO-<fcntl.h>
c++
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
大勇前进4 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu4 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile4 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白804 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端