您的位置:首页 > 财经 > 金融 > 数据大小端问题

数据大小端问题

2024/12/22 13:55:50 来源:https://blog.csdn.net/weixin_45646601/article/details/140161013  浏览:    关键词:数据大小端问题

文章目录

    • 大小端
      • 前言
      • 函数引用(接下来使用此函数对高低位进行切换)
      • 先看截取的对于大小端的定义
      • 大小端数据的直观理解[重点]
    • 对uchar数组进行取操作
      • 定义一个uint8_t的数组观察起内部内存
      • 尝试使用uint32_t 每次区 1、2、3、4byte数据
    • 提升
    • 经过上面的介绍一定对大小端有了一定的了解,那么接下来进行的是 memcpy数组到另一个数组
      • uchar[]给uchar[]
      • uint32_t[]给uint32_t[]
      • uint32_t[]给uint8_t[]
    • 本项目代码
    • 结语

大小端

前言


在讨论大小端前我们先要了解: memset 和 memcpy 函数,它们的最小单位是以字节(byte)为单位。


函数引用(接下来使用此函数对高低位进行切换)

void MainWindow::reverseArray(char *src, char *dest, uint length)
{for(uint i=0; i<length/4; i++){dest[4*i+0] = src[4*i+3];dest[4*i+1] = src[4*i+2];dest[4*i+2] = src[4*i+1];dest[4*i+3] = src[4*i];}
}

先看截取的对于大小端的定义

请添加图片描述

大小端数据的直观理解[重点]

  * 为什么要区分 大小端字节序*:0x12345678(此种写法 左侧高字节 右侧低字节)* 地址显示: 0000 0001 0002 0003* 小端显示: 78   56   34   12* 大端显示: 12   34   56   78* 我们知道当我们 memset或memcpy从内存读数时都是从低地址往出读的* 注意:我们读出来数据时是从低位读的,* 那么小端模式下(读出来的低地址数据在低位):读出来的数写到 目的地址的时候也是依次向右挤的(头插法)* 在大端模式下(读出来的低地址数据在高位):读出来的数写到 目的地址的时候是依次向右添加的(尾插法)* 此时当我们memset 1字节时读出来的是:* 小端读小端:0x 78* 大端读大端:0x 12* 小端机器上读大端数据0x 12*  * 此时当我们memset 2字节时读出来的是:* 小端读小端:0x 56 78* 大端读大端:0x 12 34* 小端机器上读大端数据:0x 34 12*  * 此时当我们memset 3字节时读出来的是:* 小端读小端:0x 34 56 78* 大端读大端:0x 12 34 56* 小端机器上读大端数据:0x 56 34 12*  * 此时当我们memset 4字节时读出来的是:* 小端读小端:0x 12 34 56 78* 大端读大端:0x 12 34 56 78* 小端机器上读大端数据:0x 78 56 34 12* */

对uchar数组进行取操作

定义一个uint8_t的数组观察起内部内存

char _32low[] ={ 0x12,0x34,0x56,0x78,0x90,0x11,0x12,0x13};
从下方图片可以看到数组[0]的地址比数组[3]的地址低

请添加图片描述
请添加图片描述

尝试使用uint32_t 每次区 1、2、3、4byte数据

	char _32low[] ={ 0x12,0x34,0x56,0x78,0x90,0x11,0x12,0x13};//小端char abca[8];reverseArray((char*)&_32low,abca,8);//这里模拟讲小端转为大端 变为{0x78,0x56,0x34,0x12,0x13,0x12,0x11,0x90}//注意数组左侧为低地址、右侧为高地址memcpy(&_32high1,abca+0,1);//由于我们是小端机器,那么memcpy后变成 0x78//注意0x56是高地址,所以在0x78的前面memcpy(&_32high2,abca+0,2);//由于我们是小端机器,那么memcpy后变成 0x5678memcpy(&_32high3,abca+0,3);//由于我们是小端机器,那么memcpy后变成 0x345678memcpy(&_32high4,abca+0,4);//由于我们是小端机器,那么memcpy后变成 0x12345678uint8_t _81;uint16_t _161;uint32_t _321;memcpy(&_81,abca+2,1);//由于我们是小端机器,那么memcpy后变成 0x34memcpy(&_161,abca+2,2);//由于我们是小端机器,那么memcpy后变成 0x1234memcpy(&_321,abca+2,4);//由于我们是小端机器,那么memcpy后变成 0x12131234

提升


经过上面的介绍一定对大小端有了一定的了解,那么接下来进行的是 memcpy数组到另一个数组

uchar[]给uchar[]

char _32low[] ={ 0x12,0x34,0x56,0x78,0x90,0x11,0x12,0x13};//小端
char abca[8];memcpy(abca,_32low,8);
//abca得到的是[0]=0x12 [1]=0x34 。。。原因是从低地址memcpy到高地址

uint32_t[]给uint32_t[]

#pragma pack(1)uint32_t u32[8]={0x12345678,0x90111213,0x14151617,0x18192021,0x22232425,0x26272829,0x30313233,0x34353637};
#pragma pack(0)uint32_t u32new[8];memcpy(u32new,u32,sizeof(uint32_t)*8);//分析一下 //地址 1000 1001 1002 1003//数据 0x13 0x12 0x11 0x90//memcpy时我们是小端的机器所以从小端memcpy(&_321,u32new+1,4);//因为我们小端设备,所以memcpy时会从低地址读写到我们的低地址 所以写出来是0x90111213

uint32_t[]给uint8_t[]

#pragma pack(1)uint32_t u32[8]={0x12345678,0x90111213,0x14151617,0x18192021,0x22232425,0x26272829,0x30313233,0x34353637};
#pragma pack(0)memcpy(abca,u32,8);//可以自行计算[结果在下方三行处]//将得到->abca[0]=0x78 [1]=0x56 [2]=0x34 [3]=0x12 [4]=0x13 [5]=0x12 [6]=0x11 [7]=0x90

本项目代码

#include <WinSock2.h>
#include <QDebug>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
bool isLittleEndian() {uint16_t number = 0x1234;uint8_t *ptr = reinterpret_cast<uint8_t*>(&number);return (ptr[0] == 0x34);
}
void MainWindow::reverseArray(char *src, char *dest, uint length)
{for(uint i=0; i<length/4; i++){dest[4*i+0] = src[4*i+3];dest[4*i+1] = src[4*i+2];dest[4*i+2] = src[4*i+1];dest[4*i+3] = src[4*i];}
}
/*** 前* 言:* 在讨论 memset 和 memcpy 函数时,它们的最小单位是以字节(byte)为单位。** 为什么要区分 大小端字节序* 如:0x12345678(此种写法 左侧高字节 右侧低字节)* 地址显示: 0000 0001 0002 0003* 小端显示: 78   56   34   12* 大端显示: 12   34   56   78* 我们知道当我们 memset或memcpy从内存读数时都是从低地址往出读的* 注意:我们读出来数据时是从低位读的,* 那么小端模式下(读出来的低地址数据在低位):读出来的数写到 目的地址的时候也是依次向右挤的(头插法)* 在大端模式下(读出来的低地址数据在高位):读出来的数写到 目的地址的时候是依次向右添加的(尾插法)* 此时当我们memset 1字节时读出来的是:* 小端读小端:0x 78* 大端读大端:0x 12* 小端机器上读大端数据0x 12*  * 此时当我们memset 2字节时读出来的是:* 小端读小端:0x 56 78* 大端读大端:0x 12 34* 小端机器上读大端数据:0x 34 12*  * 此时当我们memset 3字节时读出来的是:* 小端读小端:0x 34 56 78* 大端读大端:0x 12 34 56* 小端机器上读大端数据:0x 56 34 12*  * 此时当我们memset 4字节时读出来的是:* 小端读小端:0x 12 34 56 78* 大端读大端:0x 12 34 56 78* 小端机器上读大端数据:0x 78 56 34 12* */
void MainWindow::on_pushButton_5_clicked()
{<地址从左到右依次递增
#pragma pack(1)char _32low[] ={ 0x12,0x34,0x56,0x78,0x90,0x11,0x12,0x13};//小端uint32_t _32low_t ;memcpy(&_32low_t,_32low+0,4);//由于小端 memcpy之后变为0x78563412uint32_t _32high1,_32high2,_32high3,_32high4 ;uint8_t _81;uint16_t _161;uint32_t _321;char abca[8];reverseArray((char*)&_32low,abca,8);//这里模拟讲小端转为大端 变为{0x78,0x56,0x34,0x12,0x13,0x12,0x11,0x90}memcpy(&_32high1,abca+0,1);//由于我们是小端机器,那么memcpy后变成 0x78memcpy(&_32high2,abca+0,2);//由于我们是小端机器,那么memcpy后变成 0x5678memcpy(&_32high3,abca+0,3);//由于我们是小端机器,那么memcpy后变成 0x345678memcpy(&_32high4,abca+0,4);//由于我们是小端机器,那么memcpy后变成 0x12345678memcpy(&_81,abca+2,1);//由于我们是小端机器,那么memcpy后变成 0x34memcpy(&_161,abca+2,2);//由于我们是小端机器,那么memcpy后变成 0x1234memcpy(&_321,abca+2,4);//由于我们是小端机器,那么memcpy后变成 0x12131234memcpy(abca,_32low,8);//abca得到的是[0]=0x12 [1]=0x34 。。。原因是从低地址memcpy到高地址
#pragma pack(0)#pragma pack(1)uint32_t u32[8]={0x12345678,0x90111213,0x14151617,0x18192021,0x22232425,0x26272829,0x30313233,0x34353637};
#pragma pack(0)uint32_t u32new[8];memcpy(u32new,u32,sizeof(uint32_t)*8);//分析一下//地址 1000 1001 1002 1003//数据 0x13 0x12 0x11 0x90//memcpy时我们是小端的机器所以从小端memcpy(&_321,u32new+1,4);//因为我们小端设备,所以memcpy时会从低地址读写到我们的低地址 所以写出来是0x90111213memcpy(abca,u32,8);//将得到->abca[0]=0x78 [1]=0x56 [2]=0x34 [3]=0x12 [4]=0x13 [5]=0x12 [6]=0x11 [7]=0x90qDebug()<<"_32low = "<<QString::number(_32low_t,16);qDebug()<<"_32high ="<<QString::number(_32high4,16);if (isLittleEndian()) {std::cout << "This system is Little Endian" << std::endl;} else {std::cout << "This system is Big Endian" << std::endl;}for(int i=0 ; i<10 ; i++){static uint ss = 0;ss++;qDebug()<<ss;}}

结语


  • 如有问题欢迎指正

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com