位域 内存 字节序_C语言中的位域、字节序、比特序、大小端(转)
1.比特序
/ 位序 /?bit numbering
/
我們知道一個字節有8位,也就是8個比特位。從第0位到第7位共8位。比特序就是用來描述比特位在字節中的存放順序的。通過閱讀網頁的內容,關于比特序我們得到下面的結論:
(1)比特序分為兩種:LSB
0位序和MSB
0位序。
LSB
0位序是指:字節的第0位存放數據的,即我們的數據的最低位存放在字節的第0位。
MSB
0位序是指:字節的第0位存放,即我們的數據的最高位存放在字節的第0位。
所以說對于代碼:char *ch = 0x96;
// ?0x96 = 1001 0110
指針ch到底指向哪里呢?不難知道,如果是LSB
0位序則顯然指針ch指向最右邊的也是最低位的0.
而如果是MSB
0位序則顯然指針ch指向最左邊的也是最高位的1.
LSB 0: A container for
8-bit binary number with the highlighted?least significant bit?assigned the
bit number 0
MSB 0:A container for 8-bit
binary number with the highlighted?most significant bit?assigned the bit
number 0
(2)小端CPU通常采用的是LSB
0位序,但是大端CPU卻有可能采用LSB
0位序也有可能采用的是MSB
0位序
(Little-endian?CPUs usually employ
"LSB 0" bit numbering, however both bit numbering conventions can
be seen in?big-endianmachines. )
(3)推薦的標準是MSB
0位序。
(The
recommended style for?Request for Comments?documents is
"MSB 0" bit numbering.)
(4)Bit
numbering is usually transparent to the
In?computing, the
term?endian?or?endianness?refers
to the ordering of individually addressable sub-components within
the representation of a larger data item as stored
in?external memory?(or,
sometimes, as sent on a serial connection). Each sub-component in
the representation has a unique degree of significance, like
the?place
value?of digits in a decimal number. These
sub-components are typically 16- or
32-bit?words, 8-bit?bytes, or
even?bits.
Endianness is a difference in data representation at the hardware
level and may or may not be transparent at higher levels, depending
on factors such as the type of high level language used.
計算機中,術語“端”是指:在內存中的一個較大的數據,它是由各個可以被單獨尋址的部分組成,這些組成部分在該數據中是以怎樣的順序存放的呢?而這個問題涉及到“端”的概念,CPU是大端還是小端決定了這些組成部分的存放順序。
這些組成部分可能是16或32位的字、8位的字節、甚至是比特位。
The most common cases refer
to how bytes are ordered within a single。
我們通常碰到的情況是:字節是以怎樣的順序存放在一個16、32、64位的數據中。
(當我們要存取一個16、32、64位數據的某一組成部分,也就是某一個或幾個字節時,就要特別注意機器的“大小端”)
A?big-endian?machine
stores the?most?significant byte
first, and
a?little-endian?machine stores
the?least?significant byte
first.
Quick Reference - Byte
Machine Example
Endian
First Byte
(lowest address)
Middle Bytes
Last Byte
(highest address)
Summary
big
most?significant
...
least?significant
Similar to a number written
on paper (in
little
least?significant
...
most?significant
Arithmetic calculation
order (see
Examples of storing the
value?0A0B0C0Dh?in
memory
Big-endian
Atomic element size 8-bit,
address increment 1-byte (octet)
increasing
addresses→
...
0Ah
0Bh
0Ch
0Dh
...
The?most significant byte?(MSB) value,
which is?0Ah?in our example, is
stored at the memory location with the lowest address, the next
byte value in significance,?0Bh, is stored at the
following memory location and so on. This is akin to Left-to-Right
reading in hexadecimal order.
Atomic element size
16-bit
increasing
addresses→
...
0A0Bh
0C0Dh
...
The most significant atomic
element stores now the value?0A0Bh, followed
by?0C0Dh.
Little-endian?
Atomic element size 8-bit,
address increment 1-byte (octet)
increasing
addresses→
...
0Dh
0Ch
0Bh
0Ah
...
The?least significant byte?(LSB)
value,?0Dh, is at the lowest address. The other
bytes follow in increasing order of significance.
Atomic element size
16-bit
increasing
addresses→
...
0C0Dh
0A0Bh
...
The least significant
16-bit unit stores the value?0C0Dh, immediately
followed by?0A0Bh. Note
that?0C0Dh?and?0A0Bh?represent
integers, not bit layouts (see
很顯然“小端”機器符合“高高低低”的原則。及高位字節或字存放在高地址,低位字節或字存放在低地址。
另外“小端”機器中,數據在CPU的寄存器和內存中的存放順序是一致的。
Byte addresses increasing
from right to left
在我們寫: 0xFF86 時,很明顯地址是從右向左遞增的。也就是低位寫在右邊,高位寫在左邊。
但是當我們寫字符串時:char *str = "Hello
world!",卻是低位的字符寫在左邊,高位的字符寫在了右邊。
With 8-bit atomic
elements:
←increasing addresses
...
0Ah
0Bh
0Ch
0Dh
...
The?least significant byte?(LSB)
value,?0Dh, is at the lowest address. The other
bytes follow in increasing order of
significance.(這個明顯符合我們的習慣)
With 16-bit atomic
elements:
←increasing addresses
...
0A0Bh
0C0Dh
...
The least significant
16-bit unit stores the value?0C0Dh, immediately
followed by?0A0Bh.
The display of text is
reversed from the normal display of languages such as English that
read from left to right. For example, the word "XRAY" displayed in
this manner, with each character stored in an 8-bit atomic
element:
←increasing addresses
...
"Y"
"A"
"R"
"X"
...
(可以看到和我們手寫的順序是相反的,這一點特別要注意!)
If pairs of characters are
stored in 16-bit atomic elements (using 8 bits per character), it
could look even stranger:
←increasing addresses
...
"AY"
"XR"
...
相關的一個C例子:
#include
#include
#include
int?main()
{
char
a[]?=?{'a',?'b',?'c'};
char
b[]?=?{'d',?'e',?'f'};
a[3]?=?0;
printf("strlen(a)=%d,
strlen(b)=%d\n",?strlen(a),?strlen(b));
printf("a=%s,
b=%s\n",?a,?b);
printf("sizeof(a)=%d,
sizeof(b)=%d\n",?sizeof(a),?sizeof(b));
return
0;
}
運行結果:
strlen(a)=3,
strlen(b)=6
a=abc, b=defabc
sizeof(a)=3, sizeof(b)=3
分析:
字符數組a和b都分配在棧上,先分配a,
而a中的字符是如何分配的呢?顯然因為“寫字符串時,低位的字符寫在左邊,高位的字符寫在了右邊”。'a'是最低位,'b'在中間,而'c'在最高位。而棧是從高地址從低地址擴展的。假如是小端CPU的話,按照“高高低低”的原則,高位的'c'應該最先分配,接著是'b',最后是'a'。
分配玩字符數組a之后,在分配字符數組b,同樣的道理,高位的'f'應該最先分配,接著是'e',最后是'd'。
再執行a[3] = 0;顯然a[3]的地址應該比'c'字符的地址要高。所以該語句執行玩之后的棧的情況如下:
高地址 <
\0?c?b?a?f?e?d
所以:a字符串打印的結果是:abc,而b字符串打印的結果是:defabc.
strlen函數是計算字符串的長度,當然要找到最后的結束字符'\0',才停止計算。所以字符串a的長度是3,而字符串b的長度是6.
sizeof并不根據末尾的結束字符來計算大小。
例子2:
#include
int?main()
{
unsigned
long?array[]?=?{0x12345678,?0xabcdef01,?0x456789ab};
unsigned
short ret;
ret?=?*((unsigned
short?*)((unsigned long)array+7));
printf("0x%x\n",?ret);
return
0;
}
在“小端”CPU上結果為:0xabab。在“大端”CPU上應該為:0x0112.
例子3:
#include
#include
int?main(void){
int?a[5]={1,2,3,4,5};
int?*ptr?=(int?*)(&a+1);
printf("%d,%d\n",*(a+1),*(ptr-1))
return
0;
}
結果為:2,5
(此題與“大小端”無關。)
判斷CPU是大端還是小端的方法有有多種:
#include
#include
int?main()
{
unsigned
short x?=?0xff01;
assert(sizeof(x)?>=?2);
if(*(char*)&x?==?1)?//if(char(x)?==?1)
printf("little-endian\n");
else?if((char)x?>?1)
printf("big-endian\n");
else
printf("unknown\n");
return
0;
}
方法2:
#include
int?main()
{
union{
char
c;
int?i;
}u;
u.i?=?0x0201;
if(u.c?==?1)
printf("little-endian\n");
else?if(u.c?==?2)
printf("big-endian\n");
else
printf("unknown\n");
return
0;
}
3.C語言中的位域
先看幾個例子:
#include
union u{
struct?{
char
i:1;
char
j:2;
char
m:3;
}?s;
char
c;
}r;
int?main()
{
r.s.i?=?1;?//?1
r.s.j?=?2;?//?10
r.s.m?=?3;
//?011
printf("0x%x\n",?r.c);
return
0;
}
gcc -o union
union.c
./union
結果:0x1d (== 0001 1101
==?011?10?1)
#include
union?{
struct
{
unsigned
char a1:2;
unsigned
char a2:3;
unsigned
char a3:3;
}x;
unsigned
char b;
}d;
int?main(int?argc,?char*?argv[])
{
d.b?=?100;
//100 ==?0110 0100
printf("0x%x\n0x%x\n0x%x\n",?d.x.a1,?d.x.a2,?d.x.a3);
return
0;
}
gcc -o union2
union2.c
結果:
0x0 (==?00)
0x1 (==?001)
0x3 (==?011)
上面兩個例子的運行結果,似乎都說明:小端機器中,位域的低位組成數據的低位,位域的高位組成了數據的高位。
似乎也符合:小端CPU通常采用的是LSB
0位序的慣例。
但是這里有意個疑問:在大端CPU中,上面兩個例子的結果是什么呢?結果和小端CPU一樣嗎?結果唯一嗎?
因為前面我們說過:“但是大端CPU卻有可能采用LSB
0位序也有可能采用的是MSB
0位序”
總結
以上是生活随笔為你收集整理的位域 内存 字节序_C语言中的位域、字节序、比特序、大小端(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 魅族 20 系列手机再预热:车机实现 4
- 下一篇: 《英雄联盟》新英雄明烛“米利欧”介绍公开