文章目录
- 大小端
- 前言
- 函数引用(接下来使用此函数对高低位进行切换)
- 先看截取的对于大小端的定义
- 大小端数据的直观理解[重点]
- 对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后变成 0x5678
memcpy(&_32high3,abca+0,3);//由于我们是小端机器,那么memcpy后变成 0x345678
memcpy(&_32high4,abca+0,4);//由于我们是小端机器,那么memcpy后变成 0x12345678
uint8_t _81;
uint16_t _161;
uint32_t _321;
memcpy(&_81,abca+2,1);//由于我们是小端机器,那么memcpy后变成 0x34
memcpy(&_161,abca+2,2);//由于我们是小端机器,那么memcpy后变成 0x1234
memcpy(&_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之后变为0x78563412
uint32_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后变成 0x78
memcpy(&_32high2,abca+0,2);//由于我们是小端机器,那么memcpy后变成 0x5678
memcpy(&_32high3,abca+0,3);//由于我们是小端机器,那么memcpy后变成 0x345678
memcpy(&_32high4,abca+0,4);//由于我们是小端机器,那么memcpy后变成 0x12345678
memcpy(&_81,abca+2,1);//由于我们是小端机器,那么memcpy后变成 0x34
memcpy(&_161,abca+2,2);//由于我们是小端机器,那么memcpy后变成 0x1234
memcpy(&_321,abca+2,4);//由于我们是小端机器,那么memcpy后变成 0x12131234
memcpy(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时会从低地址读写到我们的低地址 所以写出来是0x90111213
memcpy(abca,u32,8);
//将得到->abca[0]=0x78 [1]=0x56 [2]=0x34 [3]=0x12 [4]=0x13 [5]=0x12 [6]=0x11 [7]=0x90
qDebug()<<"_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;
}
}
结语
- 如有问题欢迎指正