字节序、位序

您所在的位置:网站首页 字节序是什么意思 字节序、位序

字节序、位序

2024-07-17 20:10| 来源: 网络整理| 查看: 265

字节序

    字节序,又称端序、尾序,英文单词为Endian,该单词来源于于乔纳森·斯威夫特的小说《格列佛游记》,小说中的小人国因为吃鸡蛋的问题而内战,战争开始是由于以下的原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端。可是当今皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋时碰巧将一个手指弄破了,因此他的父亲,当时的皇帝,就下了一道敕令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。老百姓们对这项命令极为反感。历史告诉我们,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位…关于这一争端,曾出版过几百本大部著作,不过大端派的书一直是受禁的,法律也规定该派的任何人不得做官。1980年,Danny Cohen在其著名的论文"On Holy Wars and a Plea for Peace"中,为平息一场关于字节该以什么样的顺序传送的争论,而引用了该词。

        在计算机科学领域中,字节序是指存放多字节数据的字节(byte)的顺序,典型的情况是整数在内存中的存放方式和网络传输的传输顺序。有时候也可以用指位序(bit)。为了更好地理解,先看下面这段小程序,这个程序是把一个包含4位数字的字符串转换为16进制整数来存储,16进制整数的每一个字节存储一位数字字符。比如:”1234”,转换成16进制整数0x01020304。

程序1清单:

#include

#include

 

int main( )

{

    char input[4] = {0};

    int integer  = 0;

    int i;

    printf("/r/n请输入一个位数,每一位的范围是从到0到9/r/n");

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

    {

        input[i] = getch();

        if(input[i] >'9' || input[i] '9' || input[i] '9' || input[i] lsb,如下图:

 

 

小端序的机器上则正好相反

 

现代计算机的最小存储单位是BYTE,无法对bit寻址,因此我们无法直接观察每个字节内部bit的顺序。但是我们仍然可以通过位域来间接观察字节内部bit顺序,以印证上面的说法。

在C语言中,位域与结构体类似,其语法规定:先声明的成员位于低地址,后声明的成员位于高地址。那么下面的位域中:

typedefstruct OneByte

{

    bt0 : 1;

    bt1 : 1;

    bt2 : 1;

    bt3 : 1;

    bt4 : 1;

    bt5 : 1;

    bt6 : 1;

    bt7 : 1;

}

成员bt0就位于一个字节中最低地址bit0处,成员bt7就位于一个字节的最地址bit7处。

 

我们看看下面的程序。

#include

 

typedefstruct OneByte

{

    char bt0 : 1;

    char bt1 : 1;

    char bt2 : 1;

    char bt3 : 1;

    char bt4 : 1;

    char bt5 : 1;

    char bt6 : 1;

    char bt7 : 1;

} ONE_BYTE;

 

int main()

{

    ONE_BYTE onebyte = {0};

    

    onebyte.bt7 = 1;

 

    printf("onebyte = %#x/r/n", *((unsignedchar *)&onebyte));

 

    return 0;

}

 

当bt7赋值为1后,onebyte在内存中是这个样子的:

 

而在VC2005中编译运行的结果如下:

 

0x80转换成二进制是1000 0000。由于在X86(小端序)中,高地址bit7是msb,因此onebyte的值是0x80了;这就证实了前面的说法。相应的如果是在大端序计算机中,bit7是lsb,则onebyte的值是0x01。

 

 同字节序问题一样,我们来看看怎么让上面的代码在不同端序的机器上都能打印出0x01这个值呢?前面说过,不存在对单字节整数进行转换的函数"ntohc"和"htonc",那么还是用笨一点却有效的方法:针对不同的端序定义两份位域结构

typedefstruct OneByte

{

#ifdef BIG_ENDIAN   

    char bt0: 1;

    char bt1 : 1;

    char bt2 : 1;

    char bt3 : 1;

    char bt4 : 1;

    char bt5 : 1;

    char bt6 : 1;

    char bt7 : 1;

#else

    char bt7 : 1;

    char bt6 : 1;

    char bt5 : 1;

    char bt4 : 1;

    char bt3 : 1;

    char bt2 : 1;

    char bt1 : 1;

    char bt0 : 1;

#endif

} ONE_BYTE;

其实同样的用法我们在实际的代码里面就可以找到,比如linux源码tcp.h中就有如下定义:

 

struct tcphdr {     __u16    source;     __u16    dest;     __u32    seq;     __u32    ack_seq; #if defined(__LITTLE_ENDIAN_BITFIELD)     __u16    res1:4,         doff:4,         fin:1,         syn:1,         rst:1,         psh:1,         ack:1,         urg:1,         ece:1,         cwr:1; #elif defined(__BIG_ENDIAN_BITFIELD)     __u16    doff:4,         res1:4,         cwr:1,         ece:1,         urg:1,         ack:1,         psh:1,         rst:1,         syn:1,         fin:1; #else #error    "Adjust your defines" #endif        __u16    window;     __u16    check;     __u16    urg_ptr; };

 

最后一个问题,结束这篇拖了太久的文章。

既然不存在所谓的"ntohc"和"htonc"接口,那么网络通信程序是不是都要自己写代码来处理位序问题呢,尤其是底层驱动驱动程序?答案是大部分情况下不需要,因为大部分芯片都规定了串行发送一个字节的的顺序,因此发送方和接收方按照约定就能正确的接收一个字节了,可以理解为在芯片层面已经帮我们解决了位序不一致的问题。

对于上面提到的tcp.h的例子,因为tcp协议相对于底层芯片之间的通信已经是上层协议了,所以要自行处理位序。

 

拖了几年,这篇文章终于OVER了,汗颜!

 



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3