大小端、字节序问题

来源:互联网 发布:淘宝小二介入有用吗 编辑:程序博客网 时间:2024/06/05 17:23
大小端、字节序问题

大小端解析
端模式出自Jonathan Swift书写的《格列佛游记》一书,这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。
在计算机业Big Endian和Little Endian也几乎引起一场战争。在计算机业界,Endian表示数据在存储器中的存放顺序。
大端:高位存在低地址,低位存在高地址;
      小端:高位存在高地址,低位存在低地址;(intel的x86,ARM普遍都是属于小端)

举个例子,从内存地址0x0000开始有以下数据
        0x0000    0x12
        0x0001    0x34
        0x0002    0xab
        0x0003    0xcd
如果我们去读取一个地址为0x0000的四个字节变量:
        若字节序为big-endian,则读出结果为0x1234abcd;
        若字节序位little-endian,则读出结果为0xcdab3412.

如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为:
                 big-endian      little-endian
        0x0000          0x12                  0xcd
        0x0001          0x23                  0xab
        0x0002          0xab                  0x34
        0x0003          0xcd                  0x12

判断大小端的函数
int checkCPUendian()//返回1,为小端;反之,为大端;  
{  
    union  
    {  
        unsigned int  a;  
        unsigned char b;  
    }c;  
    c.a = 1;  
    return 1 == c.b;  
}  


网络字节序
我们知道网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?
数据在网络传输的过程中,也就是说: 从主机A到主机B进行通信,
A的固有数据存储---->标准化---->转化成B的固有格式
注: 标准化就是网络字节序(也是大端字节序)

网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。


在实际的工程应用中,无论主机a和b的字节序,是否一样,为了程序的可移植性和兼容性,都建议数据发送主机进行主机字节序到网络字节序的转换,数据接收机进行网络字节序到主机字节序的转换。在c++中,有4个函数可以实现主机字节序到网络字节序的相互转换,如下:
htons: 把unsigned short类型从主机序转换到网络序
   htonl: 把unsigned long类型从主机序转换到网络序
   ntohs: 把unsigned short类型从网络序转换到主机序
   ntohl: 把unsigned long类型从网络序转换到主机序

字节序的转换
1. linux + C++ 实现主机字节序和网络字节序的转换代码
#include <arpa/inet.h> //1.包含arpa/inet.h
#include <stdio.h>
int main()
{
int port=6000;
int netPort=htonl(port);
printf("netPort=%d\n",netPort);
printf("hostPort=%d\n",ntohl(netPort));
return 1;
}

output:
  netPort=1880555520
  hostPort=6000

2. Windows + C++ 实现主机字节序和网络字节序的转换代码
#include <stdio.h>
#include <Winsock2.h> //1.包含<Winsock2.h>,
#pragma comment( lib, "ws2_32.lib") //2.引入ws2_32.lib库
void main()
{
int port=6000;
int netPort=htonl(port);
printf("netPort=%d\n",netPort);
printf("hostPort=%d\n",ntohl(netPort));
}

output:
  netPort=1880555520
  hostPort=6000
原创粉丝点击