大小端和MSBLSB问题

    xiaoxiao2025-02-02  51

    一、[C/C++]大小端字节序转换程序    转自:https://www.cnblogs.com/wuyepeng/p/9833273.html

    计算机数据存储有两种字节优先顺序:高位字节优先(称为大端模式)和低位字节优先(称为小端模式)。

    大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

    小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

    例子:对于内存中存放的数0x12345678来说  如果是采用大端模式存放的,则其真实的数是:0x12345678  如果是采用小端模式存放的,则其真实的数是:0x78563412

    如果称某个系统所采用的字节序为主机字节序,则它可能是小端模式的,也可能是大端模式的。  而端口号和IP地址都是以网络字节序存储的,不是主机字节序,网络字节序都是大端模式。  要把主机字节序和网络字节序相互对应起来,需要对这两个字节存储优先顺序进行相互转化。  这里用到四个函数:htons(),ntohs(),htonl()和ntohl().  这四个地址分别实现网络字节序和主机字节序的转化,这里的h代表host,n代表network,s代表short,l代表long。  通常16位的IP端口号用s代表,而IP地址用l来代表。

    1

    2

    3

    4

    5

    6

    #include <arpa/inet.h>

     

    uint32_t htonl(uint32_t hostlong);

    uint16_t htons(uint16_t hostshort);

    uint32_t ntohl(uint32_t netlong);

    uint16_t ntohs(uint16_t netshort);

    htonl 表示 host to network long ,用于将主机 unsigned int 型数据转换成网络字节顺序;  htons 表示 host to network short ,用于将主机 unsigned short 型数据转换成网络字节顺序;  ntohl、ntohs 的功能分别与 htonl、htons 相反。  

     

     

    如图,i为int类型占4个字节,但只有1个字节的值为1,另外3个字节值为0;取出低地址上的值,当其为1时则为小端模式,为0时为大端模式。

    //大小端模式的判断 //方法一:利用联合体所有成员的起始位置一致, //对联合体中的int类型赋值,然后判断联合体中char类型的值的大小

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    95

    96

    97

    98

    99

    100

    #include <iostream>

    #include <iomanip>

    using namespace std;

     

    //signed

    typedef signed char        int8;

    typedef short              int16;

    typedef int                int32;

    typedef long long          int64;

    //unsigned

    typedef unsigned char      uint8;

    typedef unsigned short     uint16;

    typedef unsigned int       uint32;

    typedef unsigned long long uint64;

     

    #pragma pack(push)

    #pragma pack(1)//单字节对齐

    typedef struct{

        uint32 ID;

        uint32 Num;

        uint32 Type;

        uint32 lat;

        uint32 lng;

        uint32 alt;

        uint32 speed;

    }Waypoint;//Payload_Data

     

    #pragma pack(pop)

     

     

     

     

    void EndianSwap(uint8 *pData, int startIndex, int length);

     

     

     

    int main()

    {

     

        Waypoint wp,wp_ori;

        int len = sizeof(Waypoint);

        cout << "size of Waypoint: " << len << endl;

     

        wp.ID    = 0x00000011;

        wp.Num   = 0x00002200;

        wp.Type  = 0xDD0CB0AA;

        wp.lat   = 0x00330000;

        wp.lng   = 0x44000000;

        wp.alt   = 0xABCD1234;

        wp.speed = 0x12345678;

     

        wp_ori = wp;

     

     

        int i = 0;

        uint8* pData = (uint8*)(&wp);

        for (i = 0; i < len; i += 4)

        {

            EndianSwap(pData,i,4);

        }

     

     

        cout << endl;

        cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.ID << endl;

        cout << uppercase << hex << "改变字节序后: 0x" <<setfill('0') << setw(8) << wp.ID <<endl;

        cout << endl;

        cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.Num << endl;

        cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.Num << endl;

        cout << endl;

        cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.Type << endl;

        cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.Type << endl;

        cout << endl;

        cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.lat << endl;

        cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.lat << endl;

        cout << endl;

        cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.lng << endl;

        cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.lng << endl;

        cout << endl;

        cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.alt << endl;

        cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.alt << endl;

        cout << endl;

        cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.speed << endl;

        cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.speed << endl;

        return 0;

    }

     

    void EndianSwap(uint8 *pData, int startIndex, int length)

    {

        int i,cnt,end,start;

        cnt = length / 2;

        start = startIndex;

        end  = startIndex + length - 1;

        uint8 tmp;

        for (i = 0; i < cnt; i++)

        {

            tmp            = pData[start+i];

            pData[start+i] = pData[end-i];

            pData[end-i]   = tmp;

        }

    }

      运行结果如下:

     

    二、C/C++语言,对MSB、LSB的读/取处理      转自:https://blog.csdn.net/dijkstar/article/details/48765843

    1. 做硬件的都知道,串口是LSB优先,I2C、1553B是MSB优先,这里的MSB、LSB指的是二进制位的位置,区别于【字节序】(通信中,先发送低字节,还是高字节的问题,那叫大端big-endian、小端little-endian)

    如果需要自己来实现MSB、LSB的读取、转换,如何实现呢?下面给出C/C++程序:

    #include "stdio.h"   #define BITS_WIDTH    (8)   void main() {     int val = 0;     int i=0;     //     //接收:MSB在最左边,先进来     //     for (i=0; i<BITS_WIDTH; i++)     {         val<<=1;         if(i==0 || i==7)//模拟第N位上有高位             val++;     }     printf("接收MSB在最左边1,0x%x\n", val);       //     //接收:MSB在最左边,先进来     //     val = 0;     for (i=0; i<BITS_WIDTH; i++)     {         if(i==0 || i==2)//模拟第N位上有高位         {             val |=1<<(BITS_WIDTH-1-i);         }     }     printf("接收MSB在最左边2,0x%x\n", val);       //     //接收:LSB在最左边,先进来     //     val = 0;     for (i=0; i<BITS_WIDTH; i++)     {         //模拟第N位上有高位         if(i==0 || i==1)         {             val |=1<<i;         }     }     printf("接收LSB在最左边,0x%x\n", val);       printf("\n");         //     //发送: 先发送高位,后发送低位     //     val= 0x25;     printf("发送数值0x%x按先高位后低位顺序: ", val);     for (i=0; i<BITS_WIDTH; i++)     {         if ((val&0x80) == 0)             printf("0, ");         else              printf("1, ");           val <<=1;     }     printf("\n");         //     //发送: 先发送低位,后发送高位     //     val= 0x25;     printf("发送数值0x%x按先低位后高位顺序: ", val);     for (i=0; i<BITS_WIDTH; i++)     {         if ((val&0x01) == 0)             printf("0, ");         else              printf("1, ");                  val >>=1;     }     printf("\n");   }

    2. 字节序的大端、小端: x86系统用的是小端(little-endian),简单说:就是“先存储低字节,后存储高字节”,或者说“先低后高”

    例如:unsigned int xyz = 0x0A0B0C0D;

    内存中,先存储的0x0D, 0x0C, 0x0B,......,就是上面说的“先低后高”  

    最新回复(0)