数据大小端问题

news2024/12/26 7:45:17

文章目录

    • 大小端
      • 前言
      • 函数引用(接下来使用此函数对高低位进行切换)
      • 先看截取的对于大小端的定义
      • 大小端数据的直观理解[重点]
    • 对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;
    }

}

结语


  • 如有问题欢迎指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1891082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

桥梁监测系统:守护桥梁结构安全的科技利器

桥梁是城市交通的重要组成部分&#xff0c;然而&#xff0c;长期以来&#xff0c;桥梁结构的健康问题一直是人们关注的焦点。传统的人工巡检方式无法全面准确地掌握桥梁结构的实时状况&#xff0c;因此&#xff0c;桥梁监测系统应运而生。桥梁监测系统是一种基于传感器、信息处…

数据结构 - C/C++ - 树

公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 树的概念 结构特性 树的样式 树的存储 树的遍历 节点增删 二叉搜索树 平衡二叉树 树的概念 二叉树是树形结构&#xff0c;是一种非线性结构。 非线性结构&#xff1a;在二叉树中&#x…

<电力行业> - 《第15课:电力领域(一)》

1 电网 发电厂与最终用电用户&#xff08;负荷&#xff09;往往相距很远&#xff0c;因此电力需要由电厂”输送“到最终用户&#xff0c;即“输电环节“&#xff0c;电流的输送往往导致因线路发热造成损耗&#xff0c;所以在输送的时候都是通过变电升高电压&#xff0c;让电流…

C语言刷题小记

前言 本篇博客和大家分享一些C语言的OJ题目&#xff0c;希望大家可以通过这些题目进一步提升自己的编程能力&#xff0c;如果你对本篇内容感兴趣&#xff0c;可以一键三连&#xff0c;多多关注&#xff0c;下面进入正文部分。 题目1 十六进制转十进制 描述 BoBo写了一个十六…

66.Python-web框架-Django-免费模板django-datta-able的分页的一种方式

目录 1.方案介绍 1.1实现效果 1.2django.core.paginator Paginator 类: Page 类: EmptyPage 和 PageNotAnInteger 异常: 1.3 templatetags 2.方案步骤 2.1创建一个common app 2.2创建plugins/_pagination.html 2.3 其他app的views.py查询方法 2.4在AIRecords.html里…

springboot旅游管理系统-计算机毕业设计源码16021

摘 要 本文旨在设计和实现一个基于Spring Boot框架的旅游管理系统。该系统通过利用Spring Boot的快速开发特性和丰富的生态系统&#xff0c;提供了一个高效、可靠和灵活的解决方案。系统将实现旅游景点信息的管理、线路规划、跟团游玩、旅游攻略、酒店信息管理、订单管理和用户…

html+css+js文章模板

图片 源代码在图片后面&#xff0c;点赞加关注&#xff0c;谢谢&#x1f604; 源代码 <!DOCTYPE html> <html lang"zh"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width,…

JSP实现简单的登录和注册

JSP实现登录和注册&#xff08;Map集合模拟数据库&#xff09; 1、login.jsp2、 loginSelect.jsp3、register.jsp4、 RegisterSelect.jsp5、 index.jsp 1、login.jsp login.jsp中username和password在LoginSelect.jsp验证是否一致使用session.setAttribute("login_msg&quo…

Android Studio初学者实例:ContentProvider读取手机通讯录

该实验是通过ContentProvider读取手机通讯录 知识点包含了RecyclerView控件、UriMatcher、ContentResolver 先看效果&#xff0c;显示手机通讯录 首先是界面的布局代码 activity_main59.xml <?xml version"1.0" encoding"utf-8"?> <LinearL…

[译]Reactjs性能篇

英文有限&#xff0c;技术一般&#xff0c;海涵海涵&#xff0c;由于不是翻译出身&#xff0c;所以存在大量的瞎胡乱翻译的情况&#xff0c;信不过我的&#xff0c;请看原文&#xff5e;&#xff5e; 原文地址&#xff1a;https://facebook.github.io/react/docs/advanced-per…

不同操作系统下的换行符

1. 关键字2. 换行符的比较3. ASCII码4. 修改换行符 4.1. VSCode 5. 参考文档 1. 关键字 CR LF CRLF 换行符 2. 换行符的比较 英文全称英文缩写中文含义转义字符ASCII码值操作系统Carriage ReturnCR回车\r13MacIntosh&#xff08;早期的Mac&#xff09;LinefeedLF换行/新行\…

Qt Q_ASSERT详解

Q_ASSERT详解 引言一、基本用法二、深入了解三、参考链接 引言 Q_ASSERT是 Qt 框架中的一个宏&#xff0c;用于在调试时检查某个条件是否为真。它是程序调试中的一个重要工具&#xff0c;有助于开发者在开发过程中及时发现并修复潜在的错误。 一、基本用法 只在使用 Qt 的 D…

暑期大数据人工智能学习-企业项目试岗实训开营

暑期企业项目-试岗实训活动全面开启啦 跟张良均老师学大数据人工智能 不仅可以提供实习证明&#xff0c;有需要话也可以提供实习鉴定报告 √54个热门案例拆解 √40项目实战课程 √27个项目可选 √4个项目方向

数据提取的奥秘

在数字化时代&#xff0c;数据提取作为连接原始数据与知识发现的桥梁&#xff0c;其重要性不言而喻。它不仅是数据分析和数据治理的基石&#xff0c;更是企业决策和业务优化的关键。以下是数据提取奥秘的详细解析&#xff1a; 一、数据提取的定义与意义 定义&#xff1a;数据…

怎样保存python文件

按下“CtrlS”键即可快速保存Python文件。 或者点击“File”&#xff0c;在下拉菜单中选择“Save”。 打开后我们就会看到这样的一个页面窗口了。 我们还能在这里进行路径的保存位置的查找。 然后在这里选择文件类型&#xff0c;并输入文件名。 接下来我们点击保存就可以完成操…

PyCharm远程开发配置(2024以下版本)

目录 PyCharm远程开发配置 1、清理远程环境 1.1 点击Setting 1.2 进入Interpreter 1.3 删除远程环境 1.4 删除SSH 2、连接远程环境 2.1 点击Close Project 2.2 点击New Project 2.3 项目路径设置 2.4 SSH配置 2.5 选择python3解释器在远程环境的位置 2.6 配置远程…

AI Agent当牛做马,办公自动化带来超级生产力|对话Laplace

成立仅9个月的AI初创公司拉普拉斯智能&#xff08;Laplace AI&#xff09;&#xff0c;已经用原生智能生产力操作平台帮助企业用户实现智能体落地了&#xff01; 平台名为拉普拉斯智能实验室&#xff08;Laplace AI Lab&#xff09;&#xff0c;入口统一&#xff0c;用自然语言…

2024-2025年本田维修电路图线路图接线图资料更新

此次更新了2024-2025年本田车系电路图资料&#xff0c;覆盖市面上99%车型&#xff0c;包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照表位置等等&#xff01; 汽修帮手汽…

小迪安全v2023 javaWeb项目

小迪安全v2023 javaWeb项目 大体上跟随小迪安全的课程&#xff0c;本意是记录自己的学习历程&#xff0c;不能说是完全原创吧&#xff0c;大家可以关注一下小迪安全&#xff0c;他讲的挺好的。 若有冒犯&#xff0c;麻烦私信移除。 已获得迪の认可&#xff0c;哈哈 文章目录…

【Spring Boot】关系映射开发(一):一对一映射

关系映射开发&#xff08;一&#xff09;&#xff1a;一对一映射 1.认识实体间关系映射1.1 映射方向1.2 ORM 映射类型 2.实现 “一对一” 映射2.1 编写实体2.1.1 新建 Student 实体2.1.2 新建 Card 实体 2.2 编写 Repository 层2.2.1 编写 Student 实体的 Repository2.2.2 编写…