Bigendian顺序和读出来相同,littleendian和读出来顺序相反。
对于一个结构体,使用bigendian和littleendian,内部元素的顺序变化,取决于具体的元素类型。
反序的原则:
- 对于连着的几个超过一个字节(含一个字节)的元素,例如下图中的sourceport、destinationport、sequencenumber、requestnumber而言,无论大端小端,它们之间的先后顺序是不会改变的。
- 对于连着的几个小于一个字节的元素而言,例如下图中的res1+doff、fin到cwr这两组元素,这两组内部的顺序是前后颠倒的,即元素之间的顺序会因大端小端而不同,但两组之间的先后顺序依然是不变的。
- 对于一个大元素(字节倍数大小)内部的反序,实际上是按字节为单位的反序,同时也是具体bit位的全反序(即,12345678 23456789是变成98765432 87654321,而不是变成23456789 12345678,这个可以详见后文),可见下面这张图片的例子。一个十六进制数字,4个bit,两个才是1字节,所以实际上判断的是字节之间的十六进制的01和02的先后。但这里看不出是不是具体bit的先后。
- 下图中,8个一位元素的颠倒只证明了字节组内部元素之间的顺序会颠倒,但不能看出具体某个超过1bit的元素内部的所有bit位是否会颠倒。res1和doff同样只能证明前者,无法说明后者。
- 那如果是4个2bit元素的倒序,到底是只颠倒一个字节内元素间顺序不颠倒元素内顺序,还是既颠倒元素间顺序,又颠倒元素内顺序呢。其实,小元素(8bit以下)字节组内部的具体元素的倒序实际上就是按bit倒序(详见后文证明)。
- 现在,我们来看看如何探索在同一字节内的1bit以上,8bit以下小元素内部,小端机是否让每个元素内部倒序。
- 首先需要证明我的机器是小端机器。代码如下:
int main(int argc, char **argv) { union { short s; char c[sizeof(short)]; } un;//联合结构体 un.s = 0x0102; //注意是十六进制 if (sizeof(short) == 2) { if (un.c[0] == 1 && un.c[1] == 2) { printf("big-endian\n");//地址从低到高读出的数字和实际数字相同 } else if (un.c[0] == 2 && un.c[1] == 1) { printf("little-endian\n");//地址从低到高读出的数字和实际数字相反 } else { printf("unknown\n"); } } else { printf("sizeof(short) = %d\n", sizeof(short)); } exit(0); }
结果:
- 可见的确是小端机器。
- 然后我们通过c++的bitset来看看具体的每个bit位的情况。方法是,设置一个8位的bitset元素,用字符串“11100100”来初始化,然后按0到7依次输出,若结果为00100111,则证明小端机会按bit取反字节;如果是11100100,则证明小端机不会按bit取反。
- 代码如下:
#include <iostream> //#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <bitset> using namespace std; int main(int argc, char const *argv[]) { string s = "11100100"; bitset<8> bit8(s); for (int i = 0; i < s.length(); i++) { cout << bit8[i] << " "; } return 0; }
结果:
事实证明,小端机器在对结构体内元素取反的时候——大元素间和字节级小元素组间及相互之间顺序固定,大元素内部的字节级小元素内部的具体bit位,会随着小端的方式按bit位全部取反。只是读取的时候,两种机器的读取顺序各自按照自己的方式,所以读出来的,每一个具体小元素,和大元素的每一个字节元素,对应另外一种机器的值是相同的,但相互的顺序是反的。