1. 結構體中元素的地址
我們知道,結構體一般包括很多元素,結構體的大小為所有元素的大小總和(包括字節對齊)。
那麼在結構體中,不同元素之間的地址相對位置是什麼關係呢?
是先定義的元素地址在低地址還是後定義的元素地址在低地址呢?
我們通過一段代碼來測試一下(我電腦型號為R9000P,AMD處理器,x86架構,win10操作系統,DevC++)
#include <stdio.h>
typedef struct {
int a;
int b;
}Test;
Test test1;
int main() {
Test test2;
printf("test1的a地址為%d,b地址為%d\n", &test1.a, &test1.b);
printf("test2的a地址為%d,b地址為%d\n", &test2.a, &test2.b);
return 0;
}
運行結構如下圖所示
這邊一起測試了一下全局變量和局部變量的情況。
test1為全局變量(存儲在堆區),test2為局部變量(存儲在棧區)。
可以看出都是先定義的元素在低地址,後定義的元素在高地址。
2. 大小端的概念(字節大小端、位的大小端)
舉例説明字節大小端:
|
內存地址
|
0x00004000
|
0x00004001
|
0x00004002
|
0x00004003
|
|
0X12
|
0x34
|
0x56
|
0X78
|
- 如果是大端處理器:這段數代表:0x12345678;
- 如果是小段處理器:這段數代表:0x78563412 ;
可以用代碼測試一下本機的字節大小端
#include <stdio.h>
typedef union {
int a;
char b[4];
}Test;
int main() {
Test test1;
test1.a = 1;
printf("b數組的第四個元素的值為%d", test1.b[0]);
return 0;
}
運行結果如下圖
我們知道對於數組,低索引的元素是位於低地址的,根據數組b的第一個元素為1可以看出,測試電腦是字節小端模式。
對於二進制數10011101B
- 如果在內存中的位置為(LSB)10111001(MSB),則為小端模式;
- 如果內存中的位置為(MSB)10011101(LSB),則為大端模式。
繼續可以用代碼測試一下位的大小端:
#include <stdio.h>
typedef union {
int a;
struct {
unsigned int d1:1;
unsigned int d:30;
unsigned int d2:1;
}bitField;
}Test;
int main() {
Test test1;
test1.a = 1;
printf("bitField的值d1為%d\n", test1.bitField.d1);
printf("bitField的值d2為%d", test1.bitField.d2);
return 0;
}
運行結果如下圖:
通過運行結果可知,此係統的位的大小端為小端模式,d1代表最低位LSB。
再看一段代碼
#include "stdio.h"
struct kk
{
unsigned a:2;
unsigned b:3;
unsigned c:2;
unsigned d:1;
}
kt;
int main()
{
char result =3;
memcpy(&kt,&result,1);
printf(" a = %d, b = %d, c = %d, d = %d,ok/n",kt.a,kt.b,kt.c,kt.d);
return 1;
}
在sun unix上用cc編譯,結果為0,0,1,1
在2000上用VC6.0編譯,結果為3,0,0,0
C語言的位域中,每個field是嚴格按照bit地址從低到高排列的:
==============
-低->->->高-
a b c d
==============
接下來看如何解析這個字節。
在little-endian機器上,result字節中各個比特的存放排列如下所示
==============
-低->->->高-
11000000
==============
對應到四個位域,得
a=3
b=0
c=0
d=0
在big-endian機器上,result字節中各個比特的存放排列如下所示
==============
-低->->->高-
00000011
==============
對應到四個位域,得
a=0
b=0
c=1
d=1
總結:
- C語言的位域類型使用時,各個field的擺放是按從低到高的bit順序排列的。
- 把數據的存放和解析分開,就可以很容易解釋字節序的問題。