PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

前置说明

  本文作为本人csdn blog的主站的备份。(BlogID=089)

  本文发布于 2019-11-04 16:44:48,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=089)

环境说明

  无

背景


  出来工作了两年有余了,其中有很多次接触到大小端的问题,每次都是拍一下脑袋,按照记忆中的内容做东西。(小端:高地址存高字节,低地址存低字节;大端:高地址存低字节,低地址存高字节)没有做深入的理解,导致我最近遇到一个通信接口文档,文档标注的是大端模式,但是我按照自己的记忆中的大端去做,却写错了,这不是我记忆有问题,只是我没有理解到位而已。

Big endian And Little endian(大小端)


  在多个字节读写或者传输过程中,哪个字节作为高字节,哪个字节作为低字节,需要我们人为定义的。于是人们定义了大端模式和小端模式。但是我们常见的一句话:“小端:高地址存高字节,低地址存低字节;大端:高地址存低字节,低地址存高字节。”是指的多字节存储中的定义。对于多字节传输中,大端小端这样记忆或者说理解可能会出问题。

#include <iostream>
#include <iomanip>
#include <cstdint> union test_byte_order{ uint16_t a;
uint8_t b;
}test0; int main(int argc, char * argv[]){ test0.a = 0xAAFF; //byte-order-check based on union
//Notice that the basefield flag only affects the insertion/extraction of integer values (floating-point values are always interpreted in decimal base).
std::cout<<"addr of test0.a is "<<std::hex << (uint64_t)&test0.a <<std::endl;
std::string union_ret = (test0.b == 0xFF)?"little endian":"big endian";
std::cout<<union_ret<<std::endl; //byte-order-check based on pointer
uint16_t a = 0xAAFF;
uint8_t * b = (uint8_t *)&a;
std::cout<<"addr of a is "<<std::hex << (uint64_t)&a <<std::endl;
std::string pointer_ret = (*b == 0xFF)?"little endian":"big endian";
std::cout<<pointer_ret<<std::endl; return 0;
}

  gdb调试结果(符合预期)

  常见的x86 是小端模式

  现在常见的arm 支持大小端模式

多字节通信(人为约定)

  多字节通信的问题的话,其实就是你是先发送高字节,还是先发送低字节位的问题。其实如果通信文档中一般都定义了先发送高还是低字节,但是如果通信文档中换一种说法(大端模式、小端模式)的话,可能就需要思考一下,或者说需要理解一下才行。

  例如tcp/ip协议中,对于ip地址和端口号,要求的必须是网络字节序,也就是大端字节序模式。那我们到底是先发送高字节还是先发送低字节呢?其实在其他的232/485/can/蓝牙/等等通信方式中,也有同样的概念。

  那对于多字节通信中,人为定义了(注意,这里的定义的概念和多字节存储中的是同等级的,你可以理解为他们两个没有关系):

  • 大端序模式:先发送高字节,后发送低字节。
  • 小端序模式:先发送低字节,后发送高字节。

  既然上述概念是大多数人为约定的,那么可能就有这样那样的误解。所以,一般通信文档上说明了大端模式、还是小端模式外,还需要标注MSB or LSB first,或者直接注明先发高或者是低字节,避免双方出现误解。

  当然,有没有方法可以记忆多字节通信中,这种大多数人定义的概念呢?下文提供了一种我的记忆方案吧。

	//x86-64 ubuntu 18.04
uint16_t ttt = 0xAABB;
uint16_t ttt_hton = htons(ttt);//把ttt转换为网络字节序,大端模式
uint8_t array[4] = {0xAA, 0xBB, 0xCC, 0xDD};

  在c&&c++数组中,数组名字是指向的这个数组的低地址。假如我要按地址自增方向发送这个数组的数据,如果数组中先存放高字节(也就是说低地址存放高字节,或者说先发送高字节),那么这种通信方案中,字节序为大端模式。小端模式同理可得。

  但是,这仅仅是一种记忆方案。而且这是一种通用的约定,具体还是要看通信文档的定义,例如tcp/ip中的ip和端口号字节序定义就是MSB first。如果某一天,哪个人可能直接定义大端模式就是先发送低字节,也是有可能的。

后记


  总结

  大小端对于存储和通信来说,我个人认为有着不同的含义。虽然可以通过一些方法联系起来记忆。

  但是我认为,以上的内容都不是重点,是一些概念的东西,重点的是,你要明白为啥会出现这个大小端的问题?什么是字节序?为什么会有字节序这个概念就行了?

参考文献


打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

大端(big endian) 小端(little endian) --- 在多字节存储 和 多字节通信中的含义(我还是太年轻了)的更多相关文章

  1. 大端(big endian)和小端(little endian)

    http://www.cnblogs.com/Romi/archive/2012/01/10/2318551.html 当前的存储器,多以byte为访问的最小单元,当一个逻辑上的地址必须分割为物理上的 ...

  2. 大端模式 VS 小端模式

    简单点说,就是字节的存储顺序,如果数据都是单字节的,那怎么存储无所谓了,但是对于多字节数据,比如int,double等,就要考虑存储的顺序了.注意字节序是硬件层面的东西,对于软件来说通常是透明的.再说 ...

  3. intel 系列的PC机处理器是大端的还是小端的?

    intel 系列的PC机处理器是大端的还是小端的?由于要安装oracle,需要知道是大端机器还是小端的,你好,现在流行的PC,是微型处理器,也就是所谓的小端处理器. 大端处理器是由若干个微型处理器有机 ...

  4. 大端模式、小端模式和C#反转

    A.C#大端模式和小端模式. 小端(little-endian)模式:低地址上存放低字节,高地址上存放高字节. 如0x11223344→ byte[] numBytes = new byte[]{ 0 ...

  5. 大端BigEndian、小端LittleEndian与字符集编码

    BigEndian(大端):低字节在高内存地址 LittleEndian(小端):低字节在低内存地址 也就是看低字节在高内存地址还是低内存地址,也就是看低字节在前还是高字节在前,低字节在前自然是小端, ...

  6. C/C++ 工具函数 —— 大端模式和小端模式的互换

    小端模式:小在小,大在大:大端模式:小在大,大在小: uint32_t swap_endian(uint32_t val) { val = ((val << 8) & 0xFF00 ...

  7. 【C/C++开发】内存对齐(内存中的数据对齐)、大端模式及小端模式

    数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍.DWORD数据的内存起始地址能被4除尽,WORD数据的内存起始地址能被2除尽.X86 CPU能直接访问对齐的数据,当它试图访问一个未对齐的数据 ...

  8. C# 中大端序与小端序

    C# 中大端序与小端序 static void Main(string[] args) { uint value = 0x12345678; Console.WriteLine("原始字节序 ...

  9. 大端(Big Endian)与小端(Little Endian)

    1. 你从哪里来?端模式(Endian)的这个词出自Jonathan Swift书写的<格列佛游记>.这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big ...

  10. 大端字节序&小端字节序(网络字节序&主机字节序)

    大端字节序:整数的高位字节存储在内存的低地址处,低字节存储在内存的高地址处. 小端字节序:整数的高位字节存储在内存的高地址处,低字节存储在内存的低地址处. 一般pc大多采用小端字节序,也称为主机字节序 ...

随机推荐

  1. TValue 的 TTypeKind 的自动转换

    首先官方的定义: TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat, tkString, tkSet, tkClass ...

  2. pandas 用户数据分析

    import pandas as pd import numpy as np from matplotlib import pyplot as plt """ 第一部分: ...

  3. JS LeetCode 566. 重塑矩阵题解分析,数组降维的几种方式

    壹 ❀ 引 今天是过完年到公司的第二天,年前因为封版,到今天我们小组是第一个发版的组,然后就各种踩坑,到现在还在公司等运维解决jenkins问题,闲着也是闲着,做一道算法题,简单记录下解题思路,本题来 ...

  4. 从零开始的微信小程序入门教程(四),理解小程序事件与冒泡机制

    壹 ❀ 引 我在之前初识WXML与数据绑定两篇文章中,介绍了小程序静态模板与样式相关概念,以及小程序几种常用数据绑定方式,在知道这些知识后,我们可以写一些不算复杂的小程序页面,并能将一些自定义的数据渲 ...

  5. NC20909 游戏

    题目链接 题目 题目描述 有 n 个人围成一个环玩传球游戏,每轮游戏手里拿着球的那个人必须将球传给他(她)的一个朋友.游戏一共进行了 m 轮,初始球在第 a 个人手中,问游戏结束后球在第 b 个人手中 ...

  6. Python 中isinstance的用法

    isinstance()函数用来判断一个对象是否是一个已知的类型.isinstance(object, classinfo) 类似 type().isinstance() 与 type() 区别: t ...

  7. Table布局

    Table布局 <table>最常用的也是最正确的使用方法是制作表格,由于其对占据的空间有着划分的作用,便可以使用<table>来布局. 实例 实现一个简单的布局,将表格的bo ...

  8. Spring Boot图书管理系统项目实战-1.系统功能和架构介绍

    导航: next:2.项目搭建 1.项目源码 需要源码的朋友,请捐赠任意金额后留下邮箱发送:) 2.项目背景 自己闲着没事写的,供初学spring boot和在校大学生毕业设计学习交流.大神请忽略:) ...

  9. 多线程系列(十) -ReadWriteLock用法详解

    一.摘要 在上篇文章中,我们讲到ReentrantLock可以保证了只有一个线程能执行加锁的代码. 但是有些时候,这种保护显的有点过头,比如下面这个方法,它仅仅就是只读取数据,不修改数据,它实际上允许 ...

  10. C C++指针面试题零碎整理

    最基础的指针如下: int a; int* p = &a; 答:p指向a的地址,&是取a的地址.*指的是指针中取内容的符号. 2.str[]和str*的区别: char str1[] ...