字节内存储顺序
source address : http://www.linuxjournal.com/article/6788?page=0,1
1.Byte Order: the Endianness
Two types of endianness exist, big endian and little endian. Big endian refers to the method that stores the most significant byte of an integer at the lowest byte address. Little endian is the opposite; it refers to the method of storing the most significant byte of an integer at the highest byte address.
Bit order usually follows the same endianness as the byte order for a given computer system. That is, in a big endian system the most significant bit is stored at the lowest bit address; in a little endian system, the least significant bit is stored at the lowest bit address.
The bus we refer to here is the external bus we showed in the figure above. We use PCI as an example below. The bus, as we know, is an intermediary component that interconnects CPUs, devices and various other components on the system. The endianness of bus is a standard for byte/bit order that bus protocol defines and with which other components comply.
Take an example of the PCI bus known as little endian. It implies the following: among the 32 address/data bus line AD [31:0], it expects a 32-bit device and connects its most significant data line to AD31 and least significant data line to AD0. A big endian bus protocol would be the opposite.
For a partial word device connected to bus, for example, an 8-bit device, little endian bus-like PCI specifies that the eight data lines of the device be connected to AD[7:0]. For a big endian bus protocol, it would be connected to AD[24:31].
In addition, for PCI bus the protocol requires each PCI device to implement a configuration space. This is a set of configuration registers that have the same byte order as the bus.
The endianness of network protocols defines the order in which the bits and bytes of an integer field of a network protocol header are sent and received. We also introduce a term called wire address here. A lower wire address bit or byte always is transmitted and received in front of a higher wire address bit or byte.
The endianness of NIC devices usually follow the endianness of the network protocols they support, so it could be different from the endianness of the CPU on the system. Most network protocols are big endian;
4. bit field and memory storage
ex:
typedef struct { unsigned int b1:1; unsigned int b2:8; unsigned int b3:7; unsigned int b4:8; unsigned int b5:7; unsigned int b6:1;} BIT_STRUCT;
Suppose you wanted to use the same structure definition to read in bit field data on an big endian
and little endian machine and you were willing to massage the data on input before mapping the structure
to it. Suppose we started with big endian data that was 32 bits long.
Memory layout big/little endian:
Let the start of memory be adressed as below for a big endian machine...
byte 0 byte 1 byte 2 byte 3
- |B31....B25 |B24....B16 |B15....B8 |B7....B0 | Big endian
- |B7....B0 ||B15....B8 ||B24....B16||B31....B25 | Little endian
- |b1[0],b2[7:1] | b2[0], b3[6:0] | b4[7:0] | b5[6:0] , b6[0]| physical layout when bigend generates.
总结上面几点:
通常来说,对于big endian machine,它的字节序与比特序都是大端,即低地址存高位字节,bit0存高位二进制码;
现举一个例子,比特域顺序是从左到右存
ex:
union { struct { unsigned char a:1; unsigned char b:3; unsigned char c:2; }s; unsigned char x; }tb; tb.x = 0; tb.s.a = 0; tb.s.b = 2; tb.s.c = 1; tb.x = ?
left -- > right
b0 b1 b1 b3 b4 b5 b6 b7
so
little-endian bitfield: ascending order in byte(left to right)
tb.x = 0 010 10 00 = bin(0001 0100) = 0x14 = 20 0 2 1 padding
big-endian bitfield : descending order in byte (right to left)
tb.x = 0 010 01 00 = bin(0010 0100)=0x24 = 36 0 2 1 padding
test result:
avr32 studio(黑色甲壳虫icon) :
big-endian bitfield : tb.x = 36
linux gcc:
little-endian bitfield : tb.x = 20
avr atmel studio 6.0:
little-endian bitfield : tb.x = 20
another example:
typedef struct { byte ndd_p : 4; byte ndd_net : 4; word pref_field : 9; word sbits : 3; word pref_field_length : 4; } s; s stru; stru.ndd_p = 2; 0010 stru.ndd_net = 1; 0001 stru.pref_field = 0x187; 1 1000 0111 stru.sbits = 2; 010 stru.pref_field_length = 0x06; 0110
little endian machine:
|<-- 32 -->| |<-- 8 -->| byte align|<- 9 ->| |<-3->||<-4->|b0 ... b7
0100 1000 0000 0000 1110 0001 1 010 0110 ndd_p ndd_net padding pref_field sbits len 0001 0010 0000 0000 1000 0111 0110 0101 0x 12 00 87 65
big endian machine:
|<-- 32 -->| |<-- 8 -->| |<- 9 ->| |<-3->||<-4->|b0 ... b7
0010 0001 0000 0000 1 1000 0111 010 0110 ndd_p ndd_net padding pref_field sbits len 0010 0001 0000 0000 1100 0011 1010 0110 0x 21 00 c3 a6
另一种理解方式,比较直观
b7 ... b0 b7 ... b0 ... byte 0 byte 1 byte 2 byte 3 b31 ... b24 b23 ... b16 b15 ... b8 b7 ... b0 big endian b7 ... b0 b15 ... b8 b23 ... b16 b31 ... b24 little endian |<-- 32 -->| |<-- 8 -->| |<- 9 ->| |<-3->||<-4->| 0010 0001 0000 0000 1 1000 011 1 010 0110 big endian ndd_p ndd_net padding field_high8 field_low1 sbits len 0010 0001 0000 0000 1100 0011 1010 0110 0x 21 00 c3 a6 big endian member layout : from high bit end to low bit end -> b31 to b0 0001 0010 0000 0000 1000 0111 0110 010 1 little endian
ndd_net ndd_p paddind field_low8 len sbits field_high1 0x 12 00 87 65 little endian member layout : from low to high -> b0 to b31 high -- > low 其它共同点:高bit位存高位值,不因大小端改变而变
附
// bit_fields1.cpp struct Date { unsigned nWeekDay : 3; // 0..7 (3 bits) unsigned nMonthDay : 6; // 0..31 (6 bits) unsigned nMonth : 5; // 0..12 (5 bits) unsigned nYear : 8; // 0..100 (8 bits) }; int main() { }
The conceptual memory layout of an object of type Date
is shown in the following figure.
Memory Layout of Date Object
Note that nYear
is 8 bits long and would overflow the word boundary of the declared type, unsigned int. Therefore, it is begun at the beginning of a new unsigned int. It is not necessary that all bit fields fit in one object of the underlying type; new units of storage are allocated, according to the number of bits requested in the declaration.
Microsoft Specific
The ordering of data declared as bit fields is from low to high bit, as shown in the figure above.
END Microsoft Specific
If the declaration of a structure includes an unnamed field of length 0, as shown in the following example,
// bit_fields2.cpp struct Date { unsigned nWeekDay : 3; // 0..7 (3 bits) unsigned nMonthDay : 6; // 0..31 (6 bits) unsigned : 0; // Force alignment to next boundary. unsigned nMonth : 5; // 0..12 (5 bits) unsigned nYear : 8; // 0..100 (8 bits) }; int main() { }
the memory layout is as shown in the following figure.
Layout of Date Object with Zero-Length Bit Field