[C/C++]_[初级]_[大端序和小端序理解]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/infoworld/article/details/80959560

场景

  1. 在进行Socket通讯时, 因为网络字节序是 Big-Endian模式(标准), 而大部分Windows系统都是 Little Endian模式, 所以在传输数值类型的数据时, 需要把 Little Endian的内存数据转换为 Big-Endian再发送.

  2. 如果客户端和服务端都是你自己实现的代码, 可以不需要转换, 因为你自己知道字节序.

  3. 因为 Big-Endian的系统很少见,其实大部分情况下需要进行转换都是和网络相关的.

说明

  1. 不同计算机基础结构有时存储使用不同的字节顺序的数据, 我们所使用的 Intel,x86架构都是 Little-Endian模式存储数据.

  2. Big-Endian: 就是低地址存储数据高位. Little-Endian: 低地址存储数据低位.

  3. Windows系统为我们提供了两种API来处理大小端字节序处理,还是比较方便的. 如果是处理double类型的数据, 需要自己转换. 第一种是WinSock2提供的转换函数, 比如 ntohl. 另一种是标准库扩展, 比如 _byteswap_ulong. 第一种明确的是在网络字节序Big-Endian和宿主系统之间转换, 第二种是进行字节位反转, 没有明确输入输出是 Little-Endian还是 Big-Endian, 使用时要注意.

  4. 当然, 如果理解了大小端其实字节反转的原理之后也可以自己写出来,其实真没那个必要.

Big-Endian  The most significant byte is on the left end of a word.
Little-Endian   The most significant byte is on the right end of a word

ntohs   Convert a 16-bit quantity from network byte order to host byte order (big-Endian to little-Endian).
ntohl   Convert a 32-bit quantity from network byte order to host byte order (big-Endian to little-Endian).
Htons   Convert a 16-bit quantity from host byte order to network byte order (little-Endian to big-Endian).
Htonl   Convert a 32-bit quantity from host byte order to network byte order (little-Endian to big-Endian).

例子

下边的代码演示了这两种API的使用方法:

// test-big-endian.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
#include <assert.h>
#include <WinSock2.h>
#include <stdint.h>

struct Message
{
    long m_lMagicNumber;
    short m_nCommand;
    short m_nParam1;
    long m_lParam2;
};

// 判断CPU的存储是大端序还是小端序.
bool IsLittleEndian()  
{  
    union w  
    {  
        int a;  
        char b;  
    }w1;  

    w1.a = 1;  
    return (w1.b == 1);  
} 

int32_t ToBigEndian(int32_t value)
{
    if(IsLittleEndian())
        return _byteswap_ulong(value);
    else
        return value;
}

uint32_t ToLittleEndian(uint32_t value)
{
    if(IsLittleEndian())
        return value;
    else
        return _byteswap_ulong(value);
}

double ToLittleEndian(double value)
{
    if(IsLittleEndian()){
        return value;
    }else{
        auto temp = _byteswap_uint64(value);
        return *(double*)&temp;
    }
}

uint8_t ToLittleEndian(uint8_t value)
{
    if(IsLittleEndian())
        return value;
    else
        return _byteswap_ushort(value);
}

int _tmain(int argc, _TCHAR* argv[])
{
    if(!IsLittleEndian())
        return -1;

    std::cout << "Little Endian" << std::endl;

    long value = -1;
    auto value_sock_bigendian1 = htonl(value);
    auto value_byteswap_bigendial1 = ToBigEndian(value);
    assert(value_sock_bigendian1 == value_byteswap_bigendial1);
    std::cout << "1->Little Endian: " << value_sock_bigendian1 << std::endl;

    auto value_nl_1 = ntohl(value_sock_bigendian1);
    auto value_swap_1 = _byteswap_ulong((uint32_t)value_byteswap_bigendial1);

    assert(value_nl_1 == value_swap_1);
    std::cout << "to host byte : " << value_nl_1 << std::endl;

    return 0;
}

输出:

Little Endian
1->Little Endian: 4294967295
to host byte : 4294967295

参考

Windows Sockets Byte Ordering
Windows 套接字 字节排序
大端模式和小端模式
byteswap_uint64
how-do-i-convert-between-big-endian-and-little-endian-values-in-c
判断大小端序Little Endian Order

猜你喜欢

转载自blog.csdn.net/infoworld/article/details/80959560
今日推荐