PS:要转载请注明出处,本人版权所有。
PS: 这个只是基于《我自己》的理解,
如果和你的原则及想法相冲突,请谅解,勿喷。
环境说明
无
背景
出来工作了两年有余了,其中有很多次接触到大小端的问题,每次都是拍一下脑袋,按照记忆中的内容做东西。(小端:高地址存高字节,低地址存低字节;大端:高地址存低字节,低地址存高字节)没有做深入的理解,导致我最近遇到一个通信接口文档,文档标注的是大端模式,但是我按照自己的记忆中的大端去做,却写错了,这不是我记忆有问题,只是我没有理解到位而已。
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: 有问题请留言,看到后我会第一时间回复。